done
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,670 @@ | ||||
| """ Test cases for DataFrame.plot """ | ||||
| import re | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import DataFrame | ||||
| import pandas._testing as tm | ||||
| from pandas.tests.plotting.common import ( | ||||
|     _check_colors, | ||||
|     _check_plot_works, | ||||
|     _unpack_cycler, | ||||
| ) | ||||
| from pandas.util.version import Version | ||||
|  | ||||
| mpl = pytest.importorskip("matplotlib") | ||||
| plt = pytest.importorskip("matplotlib.pyplot") | ||||
| cm = pytest.importorskip("matplotlib.cm") | ||||
|  | ||||
|  | ||||
| def _check_colors_box(bp, box_c, whiskers_c, medians_c, caps_c="k", fliers_c=None): | ||||
|     if fliers_c is None: | ||||
|         fliers_c = "k" | ||||
|     _check_colors(bp["boxes"], linecolors=[box_c] * len(bp["boxes"])) | ||||
|     _check_colors(bp["whiskers"], linecolors=[whiskers_c] * len(bp["whiskers"])) | ||||
|     _check_colors(bp["medians"], linecolors=[medians_c] * len(bp["medians"])) | ||||
|     _check_colors(bp["fliers"], linecolors=[fliers_c] * len(bp["fliers"])) | ||||
|     _check_colors(bp["caps"], linecolors=[caps_c] * len(bp["caps"])) | ||||
|  | ||||
|  | ||||
| class TestDataFrameColor: | ||||
|     @pytest.mark.parametrize( | ||||
|         "color", ["C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9"] | ||||
|     ) | ||||
|     def test_mpl2_color_cycle_str(self, color): | ||||
|         # GH 15516 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((10, 3)), columns=["a", "b", "c"] | ||||
|         ) | ||||
|         _check_plot_works(df.plot, color=color) | ||||
|  | ||||
|     def test_color_single_series_list(self): | ||||
|         # GH 3486 | ||||
|         df = DataFrame({"A": [1, 2, 3]}) | ||||
|         _check_plot_works(df.plot, color=["red"]) | ||||
|  | ||||
|     @pytest.mark.parametrize("color", [(1, 0, 0), (1, 0, 0, 0.5)]) | ||||
|     def test_rgb_tuple_color(self, color): | ||||
|         # GH 16695 | ||||
|         df = DataFrame({"x": [1, 2], "y": [3, 4]}) | ||||
|         _check_plot_works(df.plot, x="x", y="y", color=color) | ||||
|  | ||||
|     def test_color_empty_string(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((10, 2))) | ||||
|         with pytest.raises(ValueError, match="Invalid color argument:"): | ||||
|             df.plot(color="") | ||||
|  | ||||
|     def test_color_and_style_arguments(self): | ||||
|         df = DataFrame({"x": [1, 2], "y": [3, 4]}) | ||||
|         # passing both 'color' and 'style' arguments should be allowed | ||||
|         # if there is no color symbol in the style strings: | ||||
|         ax = df.plot(color=["red", "black"], style=["-", "--"]) | ||||
|         # check that the linestyles are correctly set: | ||||
|         linestyle = [line.get_linestyle() for line in ax.lines] | ||||
|         assert linestyle == ["-", "--"] | ||||
|         # check that the colors are correctly set: | ||||
|         color = [line.get_color() for line in ax.lines] | ||||
|         assert color == ["red", "black"] | ||||
|         # passing both 'color' and 'style' arguments should not be allowed | ||||
|         # if there is a color symbol in the style strings: | ||||
|         msg = ( | ||||
|             "Cannot pass 'style' string with a color symbol and 'color' keyword " | ||||
|             "argument. Please use one or the other or pass 'style' without a color " | ||||
|             "symbol" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             df.plot(color=["red", "black"], style=["k-", "r--"]) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "color, expected", | ||||
|         [ | ||||
|             ("green", ["green"] * 4), | ||||
|             (["yellow", "red", "green", "blue"], ["yellow", "red", "green", "blue"]), | ||||
|         ], | ||||
|     ) | ||||
|     def test_color_and_marker(self, color, expected): | ||||
|         # GH 21003 | ||||
|         df = DataFrame(np.random.default_rng(2).random((7, 4))) | ||||
|         ax = df.plot(color=color, style="d--") | ||||
|         # check colors | ||||
|         result = [i.get_color() for i in ax.lines] | ||||
|         assert result == expected | ||||
|         # check markers and linestyles | ||||
|         assert all(i.get_linestyle() == "--" for i in ax.lines) | ||||
|         assert all(i.get_marker() == "d" for i in ax.lines) | ||||
|  | ||||
|     def test_bar_colors(self): | ||||
|         default_colors = _unpack_cycler(plt.rcParams) | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot.bar() | ||||
|         _check_colors(ax.patches[::5], facecolors=default_colors[:5]) | ||||
|  | ||||
|     def test_bar_colors_custom(self): | ||||
|         custom_colors = "rgcby" | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot.bar(color=custom_colors) | ||||
|         _check_colors(ax.patches[::5], facecolors=custom_colors) | ||||
|  | ||||
|     @pytest.mark.parametrize("colormap", ["jet", cm.jet]) | ||||
|     def test_bar_colors_cmap(self, colormap): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|  | ||||
|         ax = df.plot.bar(colormap=colormap) | ||||
|         rgba_colors = [cm.jet(n) for n in np.linspace(0, 1, 5)] | ||||
|         _check_colors(ax.patches[::5], facecolors=rgba_colors) | ||||
|  | ||||
|     def test_bar_colors_single_col(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.loc[:, [0]].plot.bar(color="DodgerBlue") | ||||
|         _check_colors([ax.patches[0]], facecolors=["DodgerBlue"]) | ||||
|  | ||||
|     def test_bar_colors_green(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot(kind="bar", color="green") | ||||
|         _check_colors(ax.patches[::5], facecolors=["green"] * 5) | ||||
|  | ||||
|     def test_bar_user_colors(self): | ||||
|         df = DataFrame( | ||||
|             {"A": range(4), "B": range(1, 5), "color": ["red", "blue", "blue", "red"]} | ||||
|         ) | ||||
|         # This should *only* work when `y` is specified, else | ||||
|         # we use one color per column | ||||
|         ax = df.plot.bar(y="A", color=df["color"]) | ||||
|         result = [p.get_facecolor() for p in ax.patches] | ||||
|         expected = [ | ||||
|             (1.0, 0.0, 0.0, 1.0), | ||||
|             (0.0, 0.0, 1.0, 1.0), | ||||
|             (0.0, 0.0, 1.0, 1.0), | ||||
|             (1.0, 0.0, 0.0, 1.0), | ||||
|         ] | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_if_scatterplot_colorbar_affects_xaxis_visibility(self): | ||||
|         # addressing issue #10611, to ensure colobar does not | ||||
|         # interfere with x-axis label and ticklabels with | ||||
|         # ipython inline backend. | ||||
|         random_array = np.random.default_rng(2).random((10, 3)) | ||||
|         df = DataFrame(random_array, columns=["A label", "B label", "C label"]) | ||||
|  | ||||
|         ax1 = df.plot.scatter(x="A label", y="B label") | ||||
|         ax2 = df.plot.scatter(x="A label", y="B label", c="C label") | ||||
|  | ||||
|         vis1 = [vis.get_visible() for vis in ax1.xaxis.get_minorticklabels()] | ||||
|         vis2 = [vis.get_visible() for vis in ax2.xaxis.get_minorticklabels()] | ||||
|         assert vis1 == vis2 | ||||
|  | ||||
|         vis1 = [vis.get_visible() for vis in ax1.xaxis.get_majorticklabels()] | ||||
|         vis2 = [vis.get_visible() for vis in ax2.xaxis.get_majorticklabels()] | ||||
|         assert vis1 == vis2 | ||||
|  | ||||
|         assert ( | ||||
|             ax1.xaxis.get_label().get_visible() == ax2.xaxis.get_label().get_visible() | ||||
|         ) | ||||
|  | ||||
|     def test_if_hexbin_xaxis_label_is_visible(self): | ||||
|         # addressing issue #10678, to ensure colobar does not | ||||
|         # interfere with x-axis label and ticklabels with | ||||
|         # ipython inline backend. | ||||
|         random_array = np.random.default_rng(2).random((10, 3)) | ||||
|         df = DataFrame(random_array, columns=["A label", "B label", "C label"]) | ||||
|  | ||||
|         ax = df.plot.hexbin("A label", "B label", gridsize=12) | ||||
|         assert all(vis.get_visible() for vis in ax.xaxis.get_minorticklabels()) | ||||
|         assert all(vis.get_visible() for vis in ax.xaxis.get_majorticklabels()) | ||||
|         assert ax.xaxis.get_label().get_visible() | ||||
|  | ||||
|     def test_if_scatterplot_colorbars_are_next_to_parent_axes(self): | ||||
|         random_array = np.random.default_rng(2).random((10, 3)) | ||||
|         df = DataFrame(random_array, columns=["A label", "B label", "C label"]) | ||||
|  | ||||
|         fig, axes = plt.subplots(1, 2) | ||||
|         df.plot.scatter("A label", "B label", c="C label", ax=axes[0]) | ||||
|         df.plot.scatter("A label", "B label", c="C label", ax=axes[1]) | ||||
|         plt.tight_layout() | ||||
|  | ||||
|         points = np.array([ax.get_position().get_points() for ax in fig.axes]) | ||||
|         axes_x_coords = points[:, :, 0] | ||||
|         parent_distance = axes_x_coords[1, :] - axes_x_coords[0, :] | ||||
|         colorbar_distance = axes_x_coords[3, :] - axes_x_coords[2, :] | ||||
|         assert np.isclose(parent_distance, colorbar_distance, atol=1e-7).all() | ||||
|  | ||||
|     @pytest.mark.parametrize("cmap", [None, "Greys"]) | ||||
|     def test_scatter_with_c_column_name_with_colors(self, cmap): | ||||
|         # https://github.com/pandas-dev/pandas/issues/34316 | ||||
|  | ||||
|         df = DataFrame( | ||||
|             [[5.1, 3.5], [4.9, 3.0], [7.0, 3.2], [6.4, 3.2], [5.9, 3.0]], | ||||
|             columns=["length", "width"], | ||||
|         ) | ||||
|         df["species"] = ["r", "r", "g", "g", "b"] | ||||
|         if cmap is not None: | ||||
|             with tm.assert_produces_warning(UserWarning, check_stacklevel=False): | ||||
|                 ax = df.plot.scatter(x=0, y=1, cmap=cmap, c="species") | ||||
|         else: | ||||
|             ax = df.plot.scatter(x=0, y=1, c="species", cmap=cmap) | ||||
|         assert ax.collections[0].colorbar is None | ||||
|  | ||||
|     def test_scatter_colors(self): | ||||
|         df = DataFrame({"a": [1, 2, 3], "b": [1, 2, 3], "c": [1, 2, 3]}) | ||||
|         with pytest.raises(TypeError, match="Specify exactly one of `c` and `color`"): | ||||
|             df.plot.scatter(x="a", y="b", c="c", color="green") | ||||
|  | ||||
|     def test_scatter_colors_not_raising_warnings(self): | ||||
|         # GH-53908. Do not raise UserWarning: No data for colormapping | ||||
|         # provided via 'c'. Parameters 'cmap' will be ignored | ||||
|         df = DataFrame({"x": [1, 2, 3], "y": [1, 2, 3]}) | ||||
|         with tm.assert_produces_warning(None): | ||||
|             df.plot.scatter(x="x", y="y", c="b") | ||||
|  | ||||
|     def test_scatter_colors_default(self): | ||||
|         df = DataFrame({"a": [1, 2, 3], "b": [1, 2, 3], "c": [1, 2, 3]}) | ||||
|         default_colors = _unpack_cycler(mpl.pyplot.rcParams) | ||||
|  | ||||
|         ax = df.plot.scatter(x="a", y="b", c="c") | ||||
|         tm.assert_numpy_array_equal( | ||||
|             ax.collections[0].get_facecolor()[0], | ||||
|             np.array(mpl.colors.ColorConverter.to_rgba(default_colors[0])), | ||||
|         ) | ||||
|  | ||||
|     def test_scatter_colors_white(self): | ||||
|         df = DataFrame({"a": [1, 2, 3], "b": [1, 2, 3], "c": [1, 2, 3]}) | ||||
|         ax = df.plot.scatter(x="a", y="b", color="white") | ||||
|         tm.assert_numpy_array_equal( | ||||
|             ax.collections[0].get_facecolor()[0], | ||||
|             np.array([1, 1, 1, 1], dtype=np.float64), | ||||
|         ) | ||||
|  | ||||
|     def test_scatter_colorbar_different_cmap(self): | ||||
|         # GH 33389 | ||||
|         df = DataFrame({"x": [1, 2, 3], "y": [1, 3, 2], "c": [1, 2, 3]}) | ||||
|         df["x2"] = df["x"] + 1 | ||||
|  | ||||
|         _, ax = plt.subplots() | ||||
|         df.plot("x", "y", c="c", kind="scatter", cmap="cividis", ax=ax) | ||||
|         df.plot("x2", "y", c="c", kind="scatter", cmap="magma", ax=ax) | ||||
|  | ||||
|         assert ax.collections[0].cmap.name == "cividis" | ||||
|         assert ax.collections[1].cmap.name == "magma" | ||||
|  | ||||
|     def test_line_colors(self): | ||||
|         custom_colors = "rgcby" | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|  | ||||
|         ax = df.plot(color=custom_colors) | ||||
|         _check_colors(ax.get_lines(), linecolors=custom_colors) | ||||
|  | ||||
|         plt.close("all") | ||||
|  | ||||
|         ax2 = df.plot(color=custom_colors) | ||||
|         lines2 = ax2.get_lines() | ||||
|  | ||||
|         for l1, l2 in zip(ax.get_lines(), lines2): | ||||
|             assert l1.get_color() == l2.get_color() | ||||
|  | ||||
|     @pytest.mark.parametrize("colormap", ["jet", cm.jet]) | ||||
|     def test_line_colors_cmap(self, colormap): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot(colormap=colormap) | ||||
|         rgba_colors = [cm.jet(n) for n in np.linspace(0, 1, len(df))] | ||||
|         _check_colors(ax.get_lines(), linecolors=rgba_colors) | ||||
|  | ||||
|     def test_line_colors_single_col(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # make color a list if plotting one column frame | ||||
|         # handles cases like df.plot(color='DodgerBlue') | ||||
|         ax = df.loc[:, [0]].plot(color="DodgerBlue") | ||||
|         _check_colors(ax.lines, linecolors=["DodgerBlue"]) | ||||
|  | ||||
|     def test_line_colors_single_color(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot(color="red") | ||||
|         _check_colors(ax.get_lines(), linecolors=["red"] * 5) | ||||
|  | ||||
|     def test_line_colors_hex(self): | ||||
|         # GH 10299 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         custom_colors = ["#FF0000", "#0000FF", "#FFFF00", "#000000", "#FFFFFF"] | ||||
|         ax = df.plot(color=custom_colors) | ||||
|         _check_colors(ax.get_lines(), linecolors=custom_colors) | ||||
|  | ||||
|     def test_dont_modify_colors(self): | ||||
|         colors = ["r", "g", "b"] | ||||
|         DataFrame(np.random.default_rng(2).random((10, 2))).plot(color=colors) | ||||
|         assert len(colors) == 3 | ||||
|  | ||||
|     def test_line_colors_and_styles_subplots(self): | ||||
|         # GH 9894 | ||||
|         default_colors = _unpack_cycler(mpl.pyplot.rcParams) | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|  | ||||
|         axes = df.plot(subplots=True) | ||||
|         for ax, c in zip(axes, list(default_colors)): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     @pytest.mark.parametrize("color", ["k", "green"]) | ||||
|     def test_line_colors_and_styles_subplots_single_color_str(self, color): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         axes = df.plot(subplots=True, color=color) | ||||
|         for ax in axes: | ||||
|             _check_colors(ax.get_lines(), linecolors=[color]) | ||||
|  | ||||
|     @pytest.mark.parametrize("color", ["rgcby", list("rgcby")]) | ||||
|     def test_line_colors_and_styles_subplots_custom_colors(self, color): | ||||
|         # GH 9894 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         axes = df.plot(color=color, subplots=True) | ||||
|         for ax, c in zip(axes, list(color)): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     def test_line_colors_and_styles_subplots_colormap_hex(self): | ||||
|         # GH 9894 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # GH 10299 | ||||
|         custom_colors = ["#FF0000", "#0000FF", "#FFFF00", "#000000", "#FFFFFF"] | ||||
|         axes = df.plot(color=custom_colors, subplots=True) | ||||
|         for ax, c in zip(axes, list(custom_colors)): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     @pytest.mark.parametrize("cmap", ["jet", cm.jet]) | ||||
|     def test_line_colors_and_styles_subplots_colormap_subplot(self, cmap): | ||||
|         # GH 9894 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         rgba_colors = [cm.jet(n) for n in np.linspace(0, 1, len(df))] | ||||
|         axes = df.plot(colormap=cmap, subplots=True) | ||||
|         for ax, c in zip(axes, rgba_colors): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     def test_line_colors_and_styles_subplots_single_col(self): | ||||
|         # GH 9894 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # make color a list if plotting one column frame | ||||
|         # handles cases like df.plot(color='DodgerBlue') | ||||
|         axes = df.loc[:, [0]].plot(color="DodgerBlue", subplots=True) | ||||
|         _check_colors(axes[0].lines, linecolors=["DodgerBlue"]) | ||||
|  | ||||
|     def test_line_colors_and_styles_subplots_single_char(self): | ||||
|         # GH 9894 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # single character style | ||||
|         axes = df.plot(style="r", subplots=True) | ||||
|         for ax in axes: | ||||
|             _check_colors(ax.get_lines(), linecolors=["r"]) | ||||
|  | ||||
|     def test_line_colors_and_styles_subplots_list_styles(self): | ||||
|         # GH 9894 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # list of styles | ||||
|         styles = list("rgcby") | ||||
|         axes = df.plot(style=styles, subplots=True) | ||||
|         for ax, c in zip(axes, styles): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     def test_area_colors(self): | ||||
|         from matplotlib.collections import PolyCollection | ||||
|  | ||||
|         custom_colors = "rgcby" | ||||
|         df = DataFrame(np.random.default_rng(2).random((5, 5))) | ||||
|  | ||||
|         ax = df.plot.area(color=custom_colors) | ||||
|         _check_colors(ax.get_lines(), linecolors=custom_colors) | ||||
|         poly = [o for o in ax.get_children() if isinstance(o, PolyCollection)] | ||||
|         _check_colors(poly, facecolors=custom_colors) | ||||
|  | ||||
|         handles, _ = ax.get_legend_handles_labels() | ||||
|         _check_colors(handles, facecolors=custom_colors) | ||||
|  | ||||
|         for h in handles: | ||||
|             assert h.get_alpha() is None | ||||
|  | ||||
|     def test_area_colors_poly(self): | ||||
|         from matplotlib import cm | ||||
|         from matplotlib.collections import PolyCollection | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).random((5, 5))) | ||||
|         ax = df.plot.area(colormap="jet") | ||||
|         jet_colors = [cm.jet(n) for n in np.linspace(0, 1, len(df))] | ||||
|         _check_colors(ax.get_lines(), linecolors=jet_colors) | ||||
|         poly = [o for o in ax.get_children() if isinstance(o, PolyCollection)] | ||||
|         _check_colors(poly, facecolors=jet_colors) | ||||
|  | ||||
|         handles, _ = ax.get_legend_handles_labels() | ||||
|         _check_colors(handles, facecolors=jet_colors) | ||||
|         for h in handles: | ||||
|             assert h.get_alpha() is None | ||||
|  | ||||
|     def test_area_colors_stacked_false(self): | ||||
|         from matplotlib import cm | ||||
|         from matplotlib.collections import PolyCollection | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).random((5, 5))) | ||||
|         jet_colors = [cm.jet(n) for n in np.linspace(0, 1, len(df))] | ||||
|         # When stacked=False, alpha is set to 0.5 | ||||
|         ax = df.plot.area(colormap=cm.jet, stacked=False) | ||||
|         _check_colors(ax.get_lines(), linecolors=jet_colors) | ||||
|         poly = [o for o in ax.get_children() if isinstance(o, PolyCollection)] | ||||
|         jet_with_alpha = [(c[0], c[1], c[2], 0.5) for c in jet_colors] | ||||
|         _check_colors(poly, facecolors=jet_with_alpha) | ||||
|  | ||||
|         handles, _ = ax.get_legend_handles_labels() | ||||
|         linecolors = jet_with_alpha | ||||
|         _check_colors(handles[: len(jet_colors)], linecolors=linecolors) | ||||
|         for h in handles: | ||||
|             assert h.get_alpha() == 0.5 | ||||
|  | ||||
|     def test_hist_colors(self): | ||||
|         default_colors = _unpack_cycler(mpl.pyplot.rcParams) | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot.hist() | ||||
|         _check_colors(ax.patches[::10], facecolors=default_colors[:5]) | ||||
|  | ||||
|     def test_hist_colors_single_custom(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         custom_colors = "rgcby" | ||||
|         ax = df.plot.hist(color=custom_colors) | ||||
|         _check_colors(ax.patches[::10], facecolors=custom_colors) | ||||
|  | ||||
|     @pytest.mark.parametrize("colormap", ["jet", cm.jet]) | ||||
|     def test_hist_colors_cmap(self, colormap): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot.hist(colormap=colormap) | ||||
|         rgba_colors = [cm.jet(n) for n in np.linspace(0, 1, 5)] | ||||
|         _check_colors(ax.patches[::10], facecolors=rgba_colors) | ||||
|  | ||||
|     def test_hist_colors_single_col(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.loc[:, [0]].plot.hist(color="DodgerBlue") | ||||
|         _check_colors([ax.patches[0]], facecolors=["DodgerBlue"]) | ||||
|  | ||||
|     def test_hist_colors_single_color(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot(kind="hist", color="green") | ||||
|         _check_colors(ax.patches[::10], facecolors=["green"] * 5) | ||||
|  | ||||
|     def test_kde_colors(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         custom_colors = "rgcby" | ||||
|         df = DataFrame(np.random.default_rng(2).random((5, 5))) | ||||
|  | ||||
|         ax = df.plot.kde(color=custom_colors) | ||||
|         _check_colors(ax.get_lines(), linecolors=custom_colors) | ||||
|  | ||||
|     @pytest.mark.parametrize("colormap", ["jet", cm.jet]) | ||||
|     def test_kde_colors_cmap(self, colormap): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot.kde(colormap=colormap) | ||||
|         rgba_colors = [cm.jet(n) for n in np.linspace(0, 1, len(df))] | ||||
|         _check_colors(ax.get_lines(), linecolors=rgba_colors) | ||||
|  | ||||
|     def test_kde_colors_and_styles_subplots(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         default_colors = _unpack_cycler(mpl.pyplot.rcParams) | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|  | ||||
|         axes = df.plot(kind="kde", subplots=True) | ||||
|         for ax, c in zip(axes, list(default_colors)): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     @pytest.mark.parametrize("colormap", ["k", "red"]) | ||||
|     def test_kde_colors_and_styles_subplots_single_col_str(self, colormap): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         axes = df.plot(kind="kde", color=colormap, subplots=True) | ||||
|         for ax in axes: | ||||
|             _check_colors(ax.get_lines(), linecolors=[colormap]) | ||||
|  | ||||
|     def test_kde_colors_and_styles_subplots_custom_color(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         custom_colors = "rgcby" | ||||
|         axes = df.plot(kind="kde", color=custom_colors, subplots=True) | ||||
|         for ax, c in zip(axes, list(custom_colors)): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     @pytest.mark.parametrize("colormap", ["jet", cm.jet]) | ||||
|     def test_kde_colors_and_styles_subplots_cmap(self, colormap): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         rgba_colors = [cm.jet(n) for n in np.linspace(0, 1, len(df))] | ||||
|         axes = df.plot(kind="kde", colormap=colormap, subplots=True) | ||||
|         for ax, c in zip(axes, rgba_colors): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     def test_kde_colors_and_styles_subplots_single_col(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # make color a list if plotting one column frame | ||||
|         # handles cases like df.plot(color='DodgerBlue') | ||||
|         axes = df.loc[:, [0]].plot(kind="kde", color="DodgerBlue", subplots=True) | ||||
|         _check_colors(axes[0].lines, linecolors=["DodgerBlue"]) | ||||
|  | ||||
|     def test_kde_colors_and_styles_subplots_single_char(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # list of styles | ||||
|         # single character style | ||||
|         axes = df.plot(kind="kde", style="r", subplots=True) | ||||
|         for ax in axes: | ||||
|             _check_colors(ax.get_lines(), linecolors=["r"]) | ||||
|  | ||||
|     def test_kde_colors_and_styles_subplots_list(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # list of styles | ||||
|         styles = list("rgcby") | ||||
|         axes = df.plot(kind="kde", style=styles, subplots=True) | ||||
|         for ax, c in zip(axes, styles): | ||||
|             _check_colors(ax.get_lines(), linecolors=[c]) | ||||
|  | ||||
|     def test_boxplot_colors(self): | ||||
|         default_colors = _unpack_cycler(mpl.pyplot.rcParams) | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         bp = df.plot.box(return_type="dict") | ||||
|         _check_colors_box( | ||||
|             bp, | ||||
|             default_colors[0], | ||||
|             default_colors[0], | ||||
|             default_colors[2], | ||||
|             default_colors[0], | ||||
|         ) | ||||
|  | ||||
|     def test_boxplot_colors_dict_colors(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         dict_colors = { | ||||
|             "boxes": "#572923", | ||||
|             "whiskers": "#982042", | ||||
|             "medians": "#804823", | ||||
|             "caps": "#123456", | ||||
|         } | ||||
|         bp = df.plot.box(color=dict_colors, sym="r+", return_type="dict") | ||||
|         _check_colors_box( | ||||
|             bp, | ||||
|             dict_colors["boxes"], | ||||
|             dict_colors["whiskers"], | ||||
|             dict_colors["medians"], | ||||
|             dict_colors["caps"], | ||||
|             "r", | ||||
|         ) | ||||
|  | ||||
|     def test_boxplot_colors_default_color(self): | ||||
|         default_colors = _unpack_cycler(mpl.pyplot.rcParams) | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # partial colors | ||||
|         dict_colors = {"whiskers": "c", "medians": "m"} | ||||
|         bp = df.plot.box(color=dict_colors, return_type="dict") | ||||
|         _check_colors_box(bp, default_colors[0], "c", "m", default_colors[0]) | ||||
|  | ||||
|     @pytest.mark.parametrize("colormap", ["jet", cm.jet]) | ||||
|     def test_boxplot_colors_cmap(self, colormap): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         bp = df.plot.box(colormap=colormap, return_type="dict") | ||||
|         jet_colors = [cm.jet(n) for n in np.linspace(0, 1, 3)] | ||||
|         _check_colors_box( | ||||
|             bp, jet_colors[0], jet_colors[0], jet_colors[2], jet_colors[0] | ||||
|         ) | ||||
|  | ||||
|     def test_boxplot_colors_single(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # string color is applied to all artists except fliers | ||||
|         bp = df.plot.box(color="DodgerBlue", return_type="dict") | ||||
|         _check_colors_box(bp, "DodgerBlue", "DodgerBlue", "DodgerBlue", "DodgerBlue") | ||||
|  | ||||
|     def test_boxplot_colors_tuple(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         # tuple is also applied to all artists except fliers | ||||
|         bp = df.plot.box(color=(0, 1, 0), sym="#123456", return_type="dict") | ||||
|         _check_colors_box(bp, (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), "#123456") | ||||
|  | ||||
|     def test_boxplot_colors_invalid(self): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         msg = re.escape( | ||||
|             "color dict contains invalid key 'xxxx'. The key must be either " | ||||
|             "['boxes', 'whiskers', 'medians', 'caps']" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             # Color contains invalid key results in ValueError | ||||
|             df.plot.box(color={"boxes": "red", "xxxx": "blue"}) | ||||
|  | ||||
|     def test_default_color_cycle(self): | ||||
|         import cycler | ||||
|  | ||||
|         colors = list("rgbk") | ||||
|         plt.rcParams["axes.prop_cycle"] = cycler.cycler("color", colors) | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 3))) | ||||
|         ax = df.plot() | ||||
|  | ||||
|         expected = _unpack_cycler(plt.rcParams)[:3] | ||||
|         _check_colors(ax.get_lines(), linecolors=expected) | ||||
|  | ||||
|     def test_no_color_bar(self): | ||||
|         df = DataFrame( | ||||
|             { | ||||
|                 "A": np.random.default_rng(2).uniform(size=20), | ||||
|                 "B": np.random.default_rng(2).uniform(size=20), | ||||
|                 "C": np.arange(20) + np.random.default_rng(2).uniform(size=20), | ||||
|             } | ||||
|         ) | ||||
|         ax = df.plot.hexbin(x="A", y="B", colorbar=None) | ||||
|         assert ax.collections[0].colorbar is None | ||||
|  | ||||
|     def test_mixing_cmap_and_colormap_raises(self): | ||||
|         df = DataFrame( | ||||
|             { | ||||
|                 "A": np.random.default_rng(2).uniform(size=20), | ||||
|                 "B": np.random.default_rng(2).uniform(size=20), | ||||
|                 "C": np.arange(20) + np.random.default_rng(2).uniform(size=20), | ||||
|             } | ||||
|         ) | ||||
|         msg = "Only specify one of `cmap` and `colormap`" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             df.plot.hexbin(x="A", y="B", cmap="YlGn", colormap="BuGn") | ||||
|  | ||||
|     def test_passed_bar_colors(self): | ||||
|         color_tuples = [(0.9, 0, 0, 1), (0, 0.9, 0, 1), (0, 0, 0.9, 1)] | ||||
|         colormap = mpl.colors.ListedColormap(color_tuples) | ||||
|         barplot = DataFrame([[1, 2, 3]]).plot(kind="bar", cmap=colormap) | ||||
|         assert color_tuples == [c.get_facecolor() for c in barplot.patches] | ||||
|  | ||||
|     def test_rcParams_bar_colors(self): | ||||
|         color_tuples = [(0.9, 0, 0, 1), (0, 0.9, 0, 1), (0, 0, 0.9, 1)] | ||||
|         with mpl.rc_context(rc={"axes.prop_cycle": mpl.cycler("color", color_tuples)}): | ||||
|             barplot = DataFrame([[1, 2, 3]]).plot(kind="bar") | ||||
|         assert color_tuples == [c.get_facecolor() for c in barplot.patches] | ||||
|  | ||||
|     def test_colors_of_columns_with_same_name(self): | ||||
|         # ISSUE 11136 -> https://github.com/pandas-dev/pandas/issues/11136 | ||||
|         # Creating a DataFrame with duplicate column labels and testing colors of them. | ||||
|         df = DataFrame({"b": [0, 1, 0], "a": [1, 2, 3]}) | ||||
|         df1 = DataFrame({"a": [2, 4, 6]}) | ||||
|         df_concat = pd.concat([df, df1], axis=1) | ||||
|         result = df_concat.plot() | ||||
|         legend = result.get_legend() | ||||
|         if Version(mpl.__version__) < Version("3.7"): | ||||
|             handles = legend.legendHandles | ||||
|         else: | ||||
|             handles = legend.legend_handles | ||||
|         for legend, line in zip(handles, result.lines): | ||||
|             assert legend.get_color() == line.get_color() | ||||
|  | ||||
|     def test_invalid_colormap(self): | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 2)), columns=["A", "B"] | ||||
|         ) | ||||
|         msg = "(is not a valid value)|(is not a known colormap)" | ||||
|         with pytest.raises((ValueError, KeyError), match=msg): | ||||
|             df.plot(colormap="invalid_colormap") | ||||
|  | ||||
|     def test_dataframe_none_color(self): | ||||
|         # GH51953 | ||||
|         df = DataFrame([[1, 2, 3]]) | ||||
|         ax = df.plot(color=None) | ||||
|         expected = _unpack_cycler(mpl.pyplot.rcParams)[:3] | ||||
|         _check_colors(ax.get_lines(), linecolors=expected) | ||||
| @ -0,0 +1,72 @@ | ||||
| """ Test cases for DataFrame.plot """ | ||||
|  | ||||
| import pytest | ||||
|  | ||||
| from pandas import DataFrame | ||||
| from pandas.tests.plotting.common import _check_visible | ||||
|  | ||||
| pytest.importorskip("matplotlib") | ||||
|  | ||||
|  | ||||
| class TestDataFramePlotsGroupby: | ||||
|     def _assert_ytickslabels_visibility(self, axes, expected): | ||||
|         for ax, exp in zip(axes, expected): | ||||
|             _check_visible(ax.get_yticklabels(), visible=exp) | ||||
|  | ||||
|     def _assert_xtickslabels_visibility(self, axes, expected): | ||||
|         for ax, exp in zip(axes, expected): | ||||
|             _check_visible(ax.get_xticklabels(), visible=exp) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kwargs, expected", | ||||
|         [ | ||||
|             # behavior without keyword | ||||
|             ({}, [True, False, True, False]), | ||||
|             # set sharey=True should be identical | ||||
|             ({"sharey": True}, [True, False, True, False]), | ||||
|             # sharey=False, all yticklabels should be visible | ||||
|             ({"sharey": False}, [True, True, True, True]), | ||||
|         ], | ||||
|     ) | ||||
|     def test_groupby_boxplot_sharey(self, kwargs, expected): | ||||
|         # https://github.com/pandas-dev/pandas/issues/20968 | ||||
|         # sharey can now be switched check whether the right | ||||
|         # pair of axes is turned on or off | ||||
|         df = DataFrame( | ||||
|             { | ||||
|                 "a": [-1.43, -0.15, -3.70, -1.43, -0.14], | ||||
|                 "b": [0.56, 0.84, 0.29, 0.56, 0.85], | ||||
|                 "c": [0, 1, 2, 3, 1], | ||||
|             }, | ||||
|             index=[0, 1, 2, 3, 4], | ||||
|         ) | ||||
|         axes = df.groupby("c").boxplot(**kwargs) | ||||
|         self._assert_ytickslabels_visibility(axes, expected) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kwargs, expected", | ||||
|         [ | ||||
|             # behavior without keyword | ||||
|             ({}, [True, True, True, True]), | ||||
|             # set sharex=False should be identical | ||||
|             ({"sharex": False}, [True, True, True, True]), | ||||
|             # sharex=True, xticklabels should be visible | ||||
|             # only for bottom plots | ||||
|             ({"sharex": True}, [False, False, True, True]), | ||||
|         ], | ||||
|     ) | ||||
|     def test_groupby_boxplot_sharex(self, kwargs, expected): | ||||
|         # https://github.com/pandas-dev/pandas/issues/20968 | ||||
|         # sharex can now be switched check whether the right | ||||
|         # pair of axes is turned on or off | ||||
|  | ||||
|         df = DataFrame( | ||||
|             { | ||||
|                 "a": [-1.43, -0.15, -3.70, -1.43, -0.14], | ||||
|                 "b": [0.56, 0.84, 0.29, 0.56, 0.85], | ||||
|                 "c": [0, 1, 2, 3, 1], | ||||
|             }, | ||||
|             index=[0, 1, 2, 3, 4], | ||||
|         ) | ||||
|         axes = df.groupby("c").boxplot(**kwargs) | ||||
|         self._assert_xtickslabels_visibility(axes, expected) | ||||
| @ -0,0 +1,272 @@ | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| import pandas.util._test_decorators as td | ||||
|  | ||||
| from pandas import ( | ||||
|     DataFrame, | ||||
|     date_range, | ||||
| ) | ||||
| from pandas.tests.plotting.common import ( | ||||
|     _check_legend_labels, | ||||
|     _check_legend_marker, | ||||
|     _check_text_labels, | ||||
| ) | ||||
| from pandas.util.version import Version | ||||
|  | ||||
| mpl = pytest.importorskip("matplotlib") | ||||
|  | ||||
|  | ||||
| class TestFrameLegend: | ||||
|     @pytest.mark.xfail( | ||||
|         reason=( | ||||
|             "Open bug in matplotlib " | ||||
|             "https://github.com/matplotlib/matplotlib/issues/11357" | ||||
|         ) | ||||
|     ) | ||||
|     def test_mixed_yerr(self): | ||||
|         # https://github.com/pandas-dev/pandas/issues/39522 | ||||
|         from matplotlib.collections import LineCollection | ||||
|         from matplotlib.lines import Line2D | ||||
|  | ||||
|         df = DataFrame([{"x": 1, "a": 1, "b": 1}, {"x": 2, "a": 2, "b": 3}]) | ||||
|  | ||||
|         ax = df.plot("x", "a", c="orange", yerr=0.1, label="orange") | ||||
|         df.plot("x", "b", c="blue", yerr=None, ax=ax, label="blue") | ||||
|  | ||||
|         legend = ax.get_legend() | ||||
|         if Version(mpl.__version__) < Version("3.7"): | ||||
|             result_handles = legend.legendHandles | ||||
|         else: | ||||
|             result_handles = legend.legend_handles | ||||
|  | ||||
|         assert isinstance(result_handles[0], LineCollection) | ||||
|         assert isinstance(result_handles[1], Line2D) | ||||
|  | ||||
|     def test_legend_false(self): | ||||
|         # https://github.com/pandas-dev/pandas/issues/40044 | ||||
|         df = DataFrame({"a": [1, 1], "b": [2, 3]}) | ||||
|         df2 = DataFrame({"d": [2.5, 2.5]}) | ||||
|  | ||||
|         ax = df.plot(legend=True, color={"a": "blue", "b": "green"}, secondary_y="b") | ||||
|         df2.plot(legend=True, color={"d": "red"}, ax=ax) | ||||
|         legend = ax.get_legend() | ||||
|         if Version(mpl.__version__) < Version("3.7"): | ||||
|             handles = legend.legendHandles | ||||
|         else: | ||||
|             handles = legend.legend_handles | ||||
|         result = [handle.get_color() for handle in handles] | ||||
|         expected = ["blue", "green", "red"] | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize("kind", ["line", "bar", "barh", "kde", "area", "hist"]) | ||||
|     def test_df_legend_labels(self, kind): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).random((3, 3)), columns=["a", "b", "c"]) | ||||
|         df2 = DataFrame( | ||||
|             np.random.default_rng(2).random((3, 3)), columns=["d", "e", "f"] | ||||
|         ) | ||||
|         df3 = DataFrame( | ||||
|             np.random.default_rng(2).random((3, 3)), columns=["g", "h", "i"] | ||||
|         ) | ||||
|         df4 = DataFrame( | ||||
|             np.random.default_rng(2).random((3, 3)), columns=["j", "k", "l"] | ||||
|         ) | ||||
|  | ||||
|         ax = df.plot(kind=kind, legend=True) | ||||
|         _check_legend_labels(ax, labels=df.columns) | ||||
|  | ||||
|         ax = df2.plot(kind=kind, legend=False, ax=ax) | ||||
|         _check_legend_labels(ax, labels=df.columns) | ||||
|  | ||||
|         ax = df3.plot(kind=kind, legend=True, ax=ax) | ||||
|         _check_legend_labels(ax, labels=df.columns.union(df3.columns)) | ||||
|  | ||||
|         ax = df4.plot(kind=kind, legend="reverse", ax=ax) | ||||
|         expected = list(df.columns.union(df3.columns)) + list(reversed(df4.columns)) | ||||
|         _check_legend_labels(ax, labels=expected) | ||||
|  | ||||
|     def test_df_legend_labels_secondary_y(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         df = DataFrame(np.random.default_rng(2).random((3, 3)), columns=["a", "b", "c"]) | ||||
|         df2 = DataFrame( | ||||
|             np.random.default_rng(2).random((3, 3)), columns=["d", "e", "f"] | ||||
|         ) | ||||
|         df3 = DataFrame( | ||||
|             np.random.default_rng(2).random((3, 3)), columns=["g", "h", "i"] | ||||
|         ) | ||||
|         # Secondary Y | ||||
|         ax = df.plot(legend=True, secondary_y="b") | ||||
|         _check_legend_labels(ax, labels=["a", "b (right)", "c"]) | ||||
|         ax = df2.plot(legend=False, ax=ax) | ||||
|         _check_legend_labels(ax, labels=["a", "b (right)", "c"]) | ||||
|         ax = df3.plot(kind="bar", legend=True, secondary_y="h", ax=ax) | ||||
|         _check_legend_labels(ax, labels=["a", "b (right)", "c", "g", "h (right)", "i"]) | ||||
|  | ||||
|     def test_df_legend_labels_time_series(self): | ||||
|         # Time Series | ||||
|         pytest.importorskip("scipy") | ||||
|         ind = date_range("1/1/2014", periods=3) | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 3)), | ||||
|             columns=["a", "b", "c"], | ||||
|             index=ind, | ||||
|         ) | ||||
|         df2 = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 3)), | ||||
|             columns=["d", "e", "f"], | ||||
|             index=ind, | ||||
|         ) | ||||
|         df3 = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 3)), | ||||
|             columns=["g", "h", "i"], | ||||
|             index=ind, | ||||
|         ) | ||||
|         ax = df.plot(legend=True, secondary_y="b") | ||||
|         _check_legend_labels(ax, labels=["a", "b (right)", "c"]) | ||||
|         ax = df2.plot(legend=False, ax=ax) | ||||
|         _check_legend_labels(ax, labels=["a", "b (right)", "c"]) | ||||
|         ax = df3.plot(legend=True, ax=ax) | ||||
|         _check_legend_labels(ax, labels=["a", "b (right)", "c", "g", "h", "i"]) | ||||
|  | ||||
|     def test_df_legend_labels_time_series_scatter(self): | ||||
|         # Time Series | ||||
|         pytest.importorskip("scipy") | ||||
|         ind = date_range("1/1/2014", periods=3) | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 3)), | ||||
|             columns=["a", "b", "c"], | ||||
|             index=ind, | ||||
|         ) | ||||
|         df2 = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 3)), | ||||
|             columns=["d", "e", "f"], | ||||
|             index=ind, | ||||
|         ) | ||||
|         df3 = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 3)), | ||||
|             columns=["g", "h", "i"], | ||||
|             index=ind, | ||||
|         ) | ||||
|         # scatter | ||||
|         ax = df.plot.scatter(x="a", y="b", label="data1") | ||||
|         _check_legend_labels(ax, labels=["data1"]) | ||||
|         ax = df2.plot.scatter(x="d", y="e", legend=False, label="data2", ax=ax) | ||||
|         _check_legend_labels(ax, labels=["data1"]) | ||||
|         ax = df3.plot.scatter(x="g", y="h", label="data3", ax=ax) | ||||
|         _check_legend_labels(ax, labels=["data1", "data3"]) | ||||
|  | ||||
|     def test_df_legend_labels_time_series_no_mutate(self): | ||||
|         pytest.importorskip("scipy") | ||||
|         ind = date_range("1/1/2014", periods=3) | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((3, 3)), | ||||
|             columns=["a", "b", "c"], | ||||
|             index=ind, | ||||
|         ) | ||||
|         # ensure label args pass through and | ||||
|         # index name does not mutate | ||||
|         # column names don't mutate | ||||
|         df5 = df.set_index("a") | ||||
|         ax = df5.plot(y="b") | ||||
|         _check_legend_labels(ax, labels=["b"]) | ||||
|         ax = df5.plot(y="b", label="LABEL_b") | ||||
|         _check_legend_labels(ax, labels=["LABEL_b"]) | ||||
|         _check_text_labels(ax.xaxis.get_label(), "a") | ||||
|         ax = df5.plot(y="c", label="LABEL_c", ax=ax) | ||||
|         _check_legend_labels(ax, labels=["LABEL_b", "LABEL_c"]) | ||||
|         assert df5.columns.tolist() == ["b", "c"] | ||||
|  | ||||
|     def test_missing_marker_multi_plots_on_same_ax(self): | ||||
|         # GH 18222 | ||||
|         df = DataFrame(data=[[1, 1, 1, 1], [2, 2, 4, 8]], columns=["x", "r", "g", "b"]) | ||||
|         _, ax = mpl.pyplot.subplots(nrows=1, ncols=3) | ||||
|         # Left plot | ||||
|         df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[0]) | ||||
|         df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[0]) | ||||
|         df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[0]) | ||||
|         _check_legend_labels(ax[0], labels=["r", "g", "b"]) | ||||
|         _check_legend_marker(ax[0], expected_markers=["o", "x", "o"]) | ||||
|         # Center plot | ||||
|         df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[1]) | ||||
|         df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[1]) | ||||
|         df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[1]) | ||||
|         _check_legend_labels(ax[1], labels=["b", "r", "g"]) | ||||
|         _check_legend_marker(ax[1], expected_markers=["o", "o", "x"]) | ||||
|         # Right plot | ||||
|         df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[2]) | ||||
|         df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[2]) | ||||
|         df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[2]) | ||||
|         _check_legend_labels(ax[2], labels=["g", "b", "r"]) | ||||
|         _check_legend_marker(ax[2], expected_markers=["x", "o", "o"]) | ||||
|  | ||||
|     def test_legend_name(self): | ||||
|         multi = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((4, 4)), | ||||
|             columns=[np.array(["a", "a", "b", "b"]), np.array(["x", "y", "x", "y"])], | ||||
|         ) | ||||
|         multi.columns.names = ["group", "individual"] | ||||
|  | ||||
|         ax = multi.plot() | ||||
|         leg_title = ax.legend_.get_title() | ||||
|         _check_text_labels(leg_title, "group,individual") | ||||
|  | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot(legend=True, ax=ax) | ||||
|         leg_title = ax.legend_.get_title() | ||||
|         _check_text_labels(leg_title, "group,individual") | ||||
|  | ||||
|         df.columns.name = "new" | ||||
|         ax = df.plot(legend=False, ax=ax) | ||||
|         leg_title = ax.legend_.get_title() | ||||
|         _check_text_labels(leg_title, "group,individual") | ||||
|  | ||||
|         ax = df.plot(legend=True, ax=ax) | ||||
|         leg_title = ax.legend_.get_title() | ||||
|         _check_text_labels(leg_title, "new") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kind", | ||||
|         [ | ||||
|             "line", | ||||
|             "bar", | ||||
|             "barh", | ||||
|             pytest.param("kde", marks=td.skip_if_no("scipy")), | ||||
|             "area", | ||||
|             "hist", | ||||
|         ], | ||||
|     ) | ||||
|     def test_no_legend(self, kind): | ||||
|         df = DataFrame(np.random.default_rng(2).random((3, 3)), columns=["a", "b", "c"]) | ||||
|         ax = df.plot(kind=kind, legend=False) | ||||
|         _check_legend_labels(ax, visible=False) | ||||
|  | ||||
|     def test_missing_markers_legend(self): | ||||
|         # 14958 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((8, 3)), columns=["A", "B", "C"] | ||||
|         ) | ||||
|         ax = df.plot(y=["A"], marker="x", linestyle="solid") | ||||
|         df.plot(y=["B"], marker="o", linestyle="dotted", ax=ax) | ||||
|         df.plot(y=["C"], marker="<", linestyle="dotted", ax=ax) | ||||
|  | ||||
|         _check_legend_labels(ax, labels=["A", "B", "C"]) | ||||
|         _check_legend_marker(ax, expected_markers=["x", "o", "<"]) | ||||
|  | ||||
|     def test_missing_markers_legend_using_style(self): | ||||
|         # 14563 | ||||
|         df = DataFrame( | ||||
|             { | ||||
|                 "A": [1, 2, 3, 4, 5, 6], | ||||
|                 "B": [2, 4, 1, 3, 2, 4], | ||||
|                 "C": [3, 3, 2, 6, 4, 2], | ||||
|                 "X": [1, 2, 3, 4, 5, 6], | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|         _, ax = mpl.pyplot.subplots() | ||||
|         for kind in "ABC": | ||||
|             df.plot("X", kind, label=kind, ax=ax, style=".") | ||||
|  | ||||
|         _check_legend_labels(ax, labels=["A", "B", "C"]) | ||||
|         _check_legend_marker(ax, expected_markers=[".", ".", "."]) | ||||
| @ -0,0 +1,752 @@ | ||||
| """ Test cases for DataFrame.plot """ | ||||
|  | ||||
| import string | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas.compat import is_platform_linux | ||||
| from pandas.compat.numpy import np_version_gte1p24 | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import ( | ||||
|     DataFrame, | ||||
|     Series, | ||||
|     date_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
| from pandas.tests.plotting.common import ( | ||||
|     _check_axes_shape, | ||||
|     _check_box_return_type, | ||||
|     _check_legend_labels, | ||||
|     _check_ticks_props, | ||||
|     _check_visible, | ||||
|     _flatten_visible, | ||||
| ) | ||||
|  | ||||
| from pandas.io.formats.printing import pprint_thing | ||||
|  | ||||
| mpl = pytest.importorskip("matplotlib") | ||||
| plt = pytest.importorskip("matplotlib.pyplot") | ||||
|  | ||||
|  | ||||
| class TestDataFramePlotsSubplots: | ||||
|     @pytest.mark.slow | ||||
|     @pytest.mark.parametrize("kind", ["bar", "barh", "line", "area"]) | ||||
|     def test_subplots(self, kind): | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 3)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|  | ||||
|         axes = df.plot(kind=kind, subplots=True, sharex=True, legend=True) | ||||
|         _check_axes_shape(axes, axes_num=3, layout=(3, 1)) | ||||
|         assert axes.shape == (3,) | ||||
|  | ||||
|         for ax, column in zip(axes, df.columns): | ||||
|             _check_legend_labels(ax, labels=[pprint_thing(column)]) | ||||
|  | ||||
|         for ax in axes[:-2]: | ||||
|             _check_visible(ax.xaxis)  # xaxis must be visible for grid | ||||
|             _check_visible(ax.get_xticklabels(), visible=False) | ||||
|             if kind != "bar": | ||||
|                 # change https://github.com/pandas-dev/pandas/issues/26714 | ||||
|                 _check_visible(ax.get_xticklabels(minor=True), visible=False) | ||||
|             _check_visible(ax.xaxis.get_label(), visible=False) | ||||
|             _check_visible(ax.get_yticklabels()) | ||||
|  | ||||
|         _check_visible(axes[-1].xaxis) | ||||
|         _check_visible(axes[-1].get_xticklabels()) | ||||
|         _check_visible(axes[-1].get_xticklabels(minor=True)) | ||||
|         _check_visible(axes[-1].xaxis.get_label()) | ||||
|         _check_visible(axes[-1].get_yticklabels()) | ||||
|  | ||||
|     @pytest.mark.slow | ||||
|     @pytest.mark.parametrize("kind", ["bar", "barh", "line", "area"]) | ||||
|     def test_subplots_no_share_x(self, kind): | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 3)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|         axes = df.plot(kind=kind, subplots=True, sharex=False) | ||||
|         for ax in axes: | ||||
|             _check_visible(ax.xaxis) | ||||
|             _check_visible(ax.get_xticklabels()) | ||||
|             _check_visible(ax.get_xticklabels(minor=True)) | ||||
|             _check_visible(ax.xaxis.get_label()) | ||||
|             _check_visible(ax.get_yticklabels()) | ||||
|  | ||||
|     @pytest.mark.slow | ||||
|     @pytest.mark.parametrize("kind", ["bar", "barh", "line", "area"]) | ||||
|     def test_subplots_no_legend(self, kind): | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 3)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|         axes = df.plot(kind=kind, subplots=True, legend=False) | ||||
|         for ax in axes: | ||||
|             assert ax.get_legend() is None | ||||
|  | ||||
|     @pytest.mark.parametrize("kind", ["line", "area"]) | ||||
|     def test_subplots_timeseries(self, kind): | ||||
|         idx = date_range(start="2014-07-01", freq="ME", periods=10) | ||||
|         df = DataFrame(np.random.default_rng(2).random((10, 3)), index=idx) | ||||
|  | ||||
|         axes = df.plot(kind=kind, subplots=True, sharex=True) | ||||
|         _check_axes_shape(axes, axes_num=3, layout=(3, 1)) | ||||
|  | ||||
|         for ax in axes[:-2]: | ||||
|             # GH 7801 | ||||
|             _check_visible(ax.xaxis)  # xaxis must be visible for grid | ||||
|             _check_visible(ax.get_xticklabels(), visible=False) | ||||
|             _check_visible(ax.get_xticklabels(minor=True), visible=False) | ||||
|             _check_visible(ax.xaxis.get_label(), visible=False) | ||||
|             _check_visible(ax.get_yticklabels()) | ||||
|  | ||||
|         _check_visible(axes[-1].xaxis) | ||||
|         _check_visible(axes[-1].get_xticklabels()) | ||||
|         _check_visible(axes[-1].get_xticklabels(minor=True)) | ||||
|         _check_visible(axes[-1].xaxis.get_label()) | ||||
|         _check_visible(axes[-1].get_yticklabels()) | ||||
|         _check_ticks_props(axes, xrot=0) | ||||
|  | ||||
|     @pytest.mark.parametrize("kind", ["line", "area"]) | ||||
|     def test_subplots_timeseries_rot(self, kind): | ||||
|         idx = date_range(start="2014-07-01", freq="ME", periods=10) | ||||
|         df = DataFrame(np.random.default_rng(2).random((10, 3)), index=idx) | ||||
|         axes = df.plot(kind=kind, subplots=True, sharex=False, rot=45, fontsize=7) | ||||
|         for ax in axes: | ||||
|             _check_visible(ax.xaxis) | ||||
|             _check_visible(ax.get_xticklabels()) | ||||
|             _check_visible(ax.get_xticklabels(minor=True)) | ||||
|             _check_visible(ax.xaxis.get_label()) | ||||
|             _check_visible(ax.get_yticklabels()) | ||||
|             _check_ticks_props(ax, xlabelsize=7, xrot=45, ylabelsize=7) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "col", ["numeric", "timedelta", "datetime_no_tz", "datetime_all_tz"] | ||||
|     ) | ||||
|     def test_subplots_timeseries_y_axis(self, col): | ||||
|         # GH16953 | ||||
|         data = { | ||||
|             "numeric": np.array([1, 2, 5]), | ||||
|             "timedelta": [ | ||||
|                 pd.Timedelta(-10, unit="s"), | ||||
|                 pd.Timedelta(10, unit="m"), | ||||
|                 pd.Timedelta(10, unit="h"), | ||||
|             ], | ||||
|             "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 = testdata.plot(y=col) | ||||
|         result = ax.get_lines()[0].get_data()[1] | ||||
|         expected = testdata[col].values | ||||
|         assert (result == expected).all() | ||||
|  | ||||
|     def test_subplots_timeseries_y_text_error(self): | ||||
|         # GH16953 | ||||
|         data = { | ||||
|             "numeric": np.array([1, 2, 5]), | ||||
|             "text": ["This", "should", "fail"], | ||||
|         } | ||||
|         testdata = DataFrame(data) | ||||
|         msg = "no numeric data to plot" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             testdata.plot(y="text") | ||||
|  | ||||
|     @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: | ||||
|             period: | ||||
|                 since period isn't yet implemented in ``select_dtypes`` | ||||
|                 and because it will need a custom value converter + | ||||
|                 tick formatter (as was done for x-axis plots) | ||||
|  | ||||
|             categorical: | ||||
|                  because it will need a custom value converter + | ||||
|                  tick formatter (also doesn't work for x-axis, as of now) | ||||
|  | ||||
|             datetime_mixed_tz: | ||||
|                 because of the way how pandas handles ``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 = 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.parametrize( | ||||
|         "layout, exp_layout", | ||||
|         [ | ||||
|             [(2, 2), (2, 2)], | ||||
|             [(-1, 2), (2, 2)], | ||||
|             [(2, -1), (2, 2)], | ||||
|             [(1, 4), (1, 4)], | ||||
|             [(-1, 4), (1, 4)], | ||||
|             [(4, -1), (4, 1)], | ||||
|         ], | ||||
|     ) | ||||
|     def test_subplots_layout_multi_column(self, layout, exp_layout): | ||||
|         # GH 6667 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 3)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|  | ||||
|         axes = df.plot(subplots=True, layout=layout) | ||||
|         _check_axes_shape(axes, axes_num=3, layout=exp_layout) | ||||
|         assert axes.shape == exp_layout | ||||
|  | ||||
|     def test_subplots_layout_multi_column_error(self): | ||||
|         # GH 6667 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 3)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|         msg = "Layout of 1x1 must be larger than required size 3" | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             df.plot(subplots=True, layout=(1, 1)) | ||||
|  | ||||
|         msg = "At least one dimension of layout must be positive" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             df.plot(subplots=True, layout=(-1, -1)) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kwargs, expected_axes_num, expected_layout, expected_shape", | ||||
|         [ | ||||
|             ({}, 1, (1, 1), (1,)), | ||||
|             ({"layout": (3, 3)}, 1, (3, 3), (3, 3)), | ||||
|         ], | ||||
|     ) | ||||
|     def test_subplots_layout_single_column( | ||||
|         self, kwargs, expected_axes_num, expected_layout, expected_shape | ||||
|     ): | ||||
|         # GH 6667 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 1)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|         axes = df.plot(subplots=True, **kwargs) | ||||
|         _check_axes_shape( | ||||
|             axes, | ||||
|             axes_num=expected_axes_num, | ||||
|             layout=expected_layout, | ||||
|         ) | ||||
|         assert axes.shape == expected_shape | ||||
|  | ||||
|     @pytest.mark.slow | ||||
|     @pytest.mark.parametrize("idx", [range(5), date_range("1/1/2000", periods=5)]) | ||||
|     def test_subplots_warnings(self, idx): | ||||
|         # GH 9464 | ||||
|         with tm.assert_produces_warning(None): | ||||
|             df = DataFrame(np.random.default_rng(2).standard_normal((5, 4)), index=idx) | ||||
|             df.plot(subplots=True, layout=(3, 2)) | ||||
|  | ||||
|     def test_subplots_multiple_axes(self): | ||||
|         # GH 5353, 6970, GH 7069 | ||||
|         fig, axes = mpl.pyplot.subplots(2, 3) | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 3)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|  | ||||
|         returned = df.plot(subplots=True, ax=axes[0], sharex=False, sharey=False) | ||||
|         _check_axes_shape(returned, axes_num=3, layout=(1, 3)) | ||||
|         assert returned.shape == (3,) | ||||
|         assert returned[0].figure is fig | ||||
|         # draw on second row | ||||
|         returned = df.plot(subplots=True, ax=axes[1], sharex=False, sharey=False) | ||||
|         _check_axes_shape(returned, axes_num=3, layout=(1, 3)) | ||||
|         assert returned.shape == (3,) | ||||
|         assert returned[0].figure is fig | ||||
|         _check_axes_shape(axes, axes_num=6, layout=(2, 3)) | ||||
|  | ||||
|     def test_subplots_multiple_axes_error(self): | ||||
|         # GH 5353, 6970, GH 7069 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 3)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|         msg = "The number of passed axes must be 3, the same as the output plot" | ||||
|         _, axes = mpl.pyplot.subplots(2, 3) | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             # pass different number of axes from required | ||||
|             df.plot(subplots=True, ax=axes) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "layout, exp_layout", | ||||
|         [ | ||||
|             [(2, 1), (2, 2)], | ||||
|             [(2, -1), (2, 2)], | ||||
|             [(-1, 2), (2, 2)], | ||||
|         ], | ||||
|     ) | ||||
|     def test_subplots_multiple_axes_2_dim(self, layout, exp_layout): | ||||
|         # GH 5353, 6970, GH 7069 | ||||
|         # pass 2-dim axes and invalid layout | ||||
|         # invalid lauout should not affect to input and return value | ||||
|         # (show warning is tested in | ||||
|         # TestDataFrameGroupByPlots.test_grouped_box_multiple_axes | ||||
|         _, axes = mpl.pyplot.subplots(2, 2) | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 4)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|         with tm.assert_produces_warning(UserWarning): | ||||
|             returned = df.plot( | ||||
|                 subplots=True, ax=axes, layout=layout, sharex=False, sharey=False | ||||
|             ) | ||||
|             _check_axes_shape(returned, axes_num=4, layout=exp_layout) | ||||
|             assert returned.shape == (4,) | ||||
|  | ||||
|     def test_subplots_multiple_axes_single_col(self): | ||||
|         # GH 5353, 6970, GH 7069 | ||||
|         # single column | ||||
|         _, axes = mpl.pyplot.subplots(1, 1) | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).random((10, 1)), | ||||
|             index=list(string.ascii_letters[:10]), | ||||
|         ) | ||||
|  | ||||
|         axes = df.plot(subplots=True, ax=[axes], sharex=False, sharey=False) | ||||
|         _check_axes_shape(axes, axes_num=1, layout=(1, 1)) | ||||
|         assert axes.shape == (1,) | ||||
|  | ||||
|     def test_subplots_ts_share_axes(self): | ||||
|         # GH 3964 | ||||
|         _, axes = mpl.pyplot.subplots(3, 3, sharex=True, sharey=True) | ||||
|         mpl.pyplot.subplots_adjust(left=0.05, right=0.95, hspace=0.3, wspace=0.3) | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((10, 9)), | ||||
|             index=date_range(start="2014-07-01", freq="ME", periods=10), | ||||
|         ) | ||||
|         for i, ax in enumerate(axes.ravel()): | ||||
|             df[i].plot(ax=ax, fontsize=5) | ||||
|  | ||||
|         # Rows other than bottom should not be visible | ||||
|         for ax in axes[0:-1].ravel(): | ||||
|             _check_visible(ax.get_xticklabels(), visible=False) | ||||
|  | ||||
|         # Bottom row should be visible | ||||
|         for ax in axes[-1].ravel(): | ||||
|             _check_visible(ax.get_xticklabels(), visible=True) | ||||
|  | ||||
|         # First column should be visible | ||||
|         for ax in axes[[0, 1, 2], [0]].ravel(): | ||||
|             _check_visible(ax.get_yticklabels(), visible=True) | ||||
|  | ||||
|         # Other columns should not be visible | ||||
|         for ax in axes[[0, 1, 2], [1]].ravel(): | ||||
|             _check_visible(ax.get_yticklabels(), visible=False) | ||||
|         for ax in axes[[0, 1, 2], [2]].ravel(): | ||||
|             _check_visible(ax.get_yticklabels(), visible=False) | ||||
|  | ||||
|     def test_subplots_sharex_axes_existing_axes(self): | ||||
|         # GH 9158 | ||||
|         d = {"A": [1.0, 2.0, 3.0, 4.0], "B": [4.0, 3.0, 2.0, 1.0], "C": [5, 1, 3, 4]} | ||||
|         df = DataFrame(d, index=date_range("2014 10 11", "2014 10 14")) | ||||
|  | ||||
|         axes = df[["A", "B"]].plot(subplots=True) | ||||
|         df["C"].plot(ax=axes[0], secondary_y=True) | ||||
|  | ||||
|         _check_visible(axes[0].get_xticklabels(), visible=False) | ||||
|         _check_visible(axes[1].get_xticklabels(), visible=True) | ||||
|         for ax in axes.ravel(): | ||||
|             _check_visible(ax.get_yticklabels(), visible=True) | ||||
|  | ||||
|     def test_subplots_dup_columns(self): | ||||
|         # GH 10962 | ||||
|         df = DataFrame(np.random.default_rng(2).random((5, 5)), columns=list("aaaaa")) | ||||
|         axes = df.plot(subplots=True) | ||||
|         for ax in axes: | ||||
|             _check_legend_labels(ax, labels=["a"]) | ||||
|             assert len(ax.lines) == 1 | ||||
|  | ||||
|     def test_subplots_dup_columns_secondary_y(self): | ||||
|         # GH 10962 | ||||
|         df = DataFrame(np.random.default_rng(2).random((5, 5)), columns=list("aaaaa")) | ||||
|         axes = df.plot(subplots=True, secondary_y="a") | ||||
|         for ax in axes: | ||||
|             # (right) is only attached when subplots=False | ||||
|             _check_legend_labels(ax, labels=["a"]) | ||||
|             assert len(ax.lines) == 1 | ||||
|  | ||||
|     def test_subplots_dup_columns_secondary_y_no_subplot(self): | ||||
|         # GH 10962 | ||||
|         df = DataFrame(np.random.default_rng(2).random((5, 5)), columns=list("aaaaa")) | ||||
|         ax = df.plot(secondary_y="a") | ||||
|         _check_legend_labels(ax, labels=["a (right)"] * 5) | ||||
|         assert len(ax.lines) == 0 | ||||
|         assert len(ax.right_ax.lines) == 5 | ||||
|  | ||||
|     @pytest.mark.xfail( | ||||
|         np_version_gte1p24 and is_platform_linux(), | ||||
|         reason="Weird rounding problems", | ||||
|         strict=False, | ||||
|     ) | ||||
|     def test_bar_log_no_subplots(self): | ||||
|         # GH3254, GH3298 matplotlib/matplotlib#1882, #1892 | ||||
|         # regressions in 1.2.1 | ||||
|         expected = np.array([0.1, 1.0, 10.0, 100]) | ||||
|  | ||||
|         # no subplots | ||||
|         df = DataFrame({"A": [3] * 5, "B": list(range(1, 6))}, index=range(5)) | ||||
|         ax = df.plot.bar(grid=True, log=True) | ||||
|         tm.assert_numpy_array_equal(ax.yaxis.get_ticklocs(), expected) | ||||
|  | ||||
|     @pytest.mark.xfail( | ||||
|         np_version_gte1p24 and is_platform_linux(), | ||||
|         reason="Weird rounding problems", | ||||
|         strict=False, | ||||
|     ) | ||||
|     def test_bar_log_subplots(self): | ||||
|         expected = np.array([0.1, 1.0, 10.0, 100.0, 1000.0, 1e4]) | ||||
|  | ||||
|         ax = DataFrame([Series([200, 300]), Series([300, 500])]).plot.bar( | ||||
|             log=True, subplots=True | ||||
|         ) | ||||
|  | ||||
|         tm.assert_numpy_array_equal(ax[0].yaxis.get_ticklocs(), expected) | ||||
|         tm.assert_numpy_array_equal(ax[1].yaxis.get_ticklocs(), expected) | ||||
|  | ||||
|     def test_boxplot_subplots_return_type_default(self, hist_df): | ||||
|         df = hist_df | ||||
|  | ||||
|         # normal style: return_type=None | ||||
|         result = df.plot.box(subplots=True) | ||||
|         assert isinstance(result, Series) | ||||
|         _check_box_return_type( | ||||
|             result, None, expected_keys=["height", "weight", "category"] | ||||
|         ) | ||||
|  | ||||
|     @pytest.mark.parametrize("rt", ["dict", "axes", "both"]) | ||||
|     def test_boxplot_subplots_return_type(self, hist_df, rt): | ||||
|         df = hist_df | ||||
|         returned = df.plot.box(return_type=rt, subplots=True) | ||||
|         _check_box_return_type( | ||||
|             returned, | ||||
|             rt, | ||||
|             expected_keys=["height", "weight", "category"], | ||||
|             check_ax_title=False, | ||||
|         ) | ||||
|  | ||||
|     def test_df_subplots_patterns_minorticks(self): | ||||
|         # GH 10657 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((10, 2)), | ||||
|             index=date_range("1/1/2000", periods=10), | ||||
|             columns=list("AB"), | ||||
|         ) | ||||
|  | ||||
|         # shared subplots | ||||
|         _, axes = plt.subplots(2, 1, sharex=True) | ||||
|         axes = df.plot(subplots=True, ax=axes) | ||||
|         for ax in axes: | ||||
|             assert len(ax.lines) == 1 | ||||
|             _check_visible(ax.get_yticklabels(), visible=True) | ||||
|         # xaxis of 1st ax must be hidden | ||||
|         _check_visible(axes[0].get_xticklabels(), visible=False) | ||||
|         _check_visible(axes[0].get_xticklabels(minor=True), visible=False) | ||||
|         _check_visible(axes[1].get_xticklabels(), visible=True) | ||||
|         _check_visible(axes[1].get_xticklabels(minor=True), visible=True) | ||||
|  | ||||
|     def test_df_subplots_patterns_minorticks_1st_ax_hidden(self): | ||||
|         # GH 10657 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((10, 2)), | ||||
|             index=date_range("1/1/2000", periods=10), | ||||
|             columns=list("AB"), | ||||
|         ) | ||||
|         _, axes = plt.subplots(2, 1) | ||||
|         with tm.assert_produces_warning(UserWarning): | ||||
|             axes = df.plot(subplots=True, ax=axes, sharex=True) | ||||
|         for ax in axes: | ||||
|             assert len(ax.lines) == 1 | ||||
|             _check_visible(ax.get_yticklabels(), visible=True) | ||||
|         # xaxis of 1st ax must be hidden | ||||
|         _check_visible(axes[0].get_xticklabels(), visible=False) | ||||
|         _check_visible(axes[0].get_xticklabels(minor=True), visible=False) | ||||
|         _check_visible(axes[1].get_xticklabels(), visible=True) | ||||
|         _check_visible(axes[1].get_xticklabels(minor=True), visible=True) | ||||
|  | ||||
|     def test_df_subplots_patterns_minorticks_not_shared(self): | ||||
|         # GH 10657 | ||||
|         df = DataFrame( | ||||
|             np.random.default_rng(2).standard_normal((10, 2)), | ||||
|             index=date_range("1/1/2000", periods=10), | ||||
|             columns=list("AB"), | ||||
|         ) | ||||
|         # not shared | ||||
|         _, axes = plt.subplots(2, 1) | ||||
|         axes = df.plot(subplots=True, ax=axes) | ||||
|         for ax in axes: | ||||
|             assert len(ax.lines) == 1 | ||||
|             _check_visible(ax.get_yticklabels(), visible=True) | ||||
|             _check_visible(ax.get_xticklabels(), visible=True) | ||||
|             _check_visible(ax.get_xticklabels(minor=True), visible=True) | ||||
|  | ||||
|     def test_subplots_sharex_false(self): | ||||
|         # test when sharex is set to False, two plots should have different | ||||
|         # labels, GH 25160 | ||||
|         df = DataFrame(np.random.default_rng(2).random((10, 2))) | ||||
|         df.iloc[5:, 1] = np.nan | ||||
|         df.iloc[:5, 0] = np.nan | ||||
|  | ||||
|         _, axs = mpl.pyplot.subplots(2, 1) | ||||
|         df.plot.line(ax=axs, subplots=True, sharex=False) | ||||
|  | ||||
|         expected_ax1 = np.arange(4.5, 10, 0.5) | ||||
|         expected_ax2 = np.arange(-0.5, 5, 0.5) | ||||
|  | ||||
|         tm.assert_numpy_array_equal(axs[0].get_xticks(), expected_ax1) | ||||
|         tm.assert_numpy_array_equal(axs[1].get_xticks(), expected_ax2) | ||||
|  | ||||
|     def test_subplots_constrained_layout(self): | ||||
|         # GH 25261 | ||||
|         idx = date_range(start="now", periods=10) | ||||
|         df = DataFrame(np.random.default_rng(2).random((10, 3)), index=idx) | ||||
|         kwargs = {} | ||||
|         if hasattr(mpl.pyplot.Figure, "get_constrained_layout"): | ||||
|             kwargs["constrained_layout"] = True | ||||
|         _, axes = mpl.pyplot.subplots(2, **kwargs) | ||||
|         with tm.assert_produces_warning(None): | ||||
|             df.plot(ax=axes[0]) | ||||
|             with tm.ensure_clean(return_filelike=True) as path: | ||||
|                 mpl.pyplot.savefig(path) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "index_name, old_label, new_label", | ||||
|         [ | ||||
|             (None, "", "new"), | ||||
|             ("old", "old", "new"), | ||||
|             (None, "", ""), | ||||
|             (None, "", 1), | ||||
|             (None, "", [1, 2]), | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize("kind", ["line", "area", "bar"]) | ||||
|     def test_xlabel_ylabel_dataframe_subplots( | ||||
|         self, kind, index_name, old_label, new_label | ||||
|     ): | ||||
|         # GH 9093 | ||||
|         df = DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) | ||||
|         df.index.name = index_name | ||||
|  | ||||
|         # default is the ylabel is not shown and xlabel is index name | ||||
|         axes = df.plot(kind=kind, subplots=True) | ||||
|         assert all(ax.get_ylabel() == "" for ax in axes) | ||||
|         assert all(ax.get_xlabel() == old_label for ax in axes) | ||||
|  | ||||
|         # old xlabel will be overridden and assigned ylabel will be used as ylabel | ||||
|         axes = df.plot(kind=kind, ylabel=new_label, xlabel=new_label, subplots=True) | ||||
|         assert all(ax.get_ylabel() == str(new_label) for ax in axes) | ||||
|         assert all(ax.get_xlabel() == str(new_label) for ax in axes) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kwargs", | ||||
|         [ | ||||
|             # stacked center | ||||
|             {"kind": "bar", "stacked": True}, | ||||
|             {"kind": "bar", "stacked": True, "width": 0.9}, | ||||
|             {"kind": "barh", "stacked": True}, | ||||
|             {"kind": "barh", "stacked": True, "width": 0.9}, | ||||
|             # center | ||||
|             {"kind": "bar", "stacked": False}, | ||||
|             {"kind": "bar", "stacked": False, "width": 0.9}, | ||||
|             {"kind": "barh", "stacked": False}, | ||||
|             {"kind": "barh", "stacked": False, "width": 0.9}, | ||||
|             # subplots center | ||||
|             {"kind": "bar", "subplots": True}, | ||||
|             {"kind": "bar", "subplots": True, "width": 0.9}, | ||||
|             {"kind": "barh", "subplots": True}, | ||||
|             {"kind": "barh", "subplots": True, "width": 0.9}, | ||||
|             # align edge | ||||
|             {"kind": "bar", "stacked": True, "align": "edge"}, | ||||
|             {"kind": "bar", "stacked": True, "width": 0.9, "align": "edge"}, | ||||
|             {"kind": "barh", "stacked": True, "align": "edge"}, | ||||
|             {"kind": "barh", "stacked": True, "width": 0.9, "align": "edge"}, | ||||
|             {"kind": "bar", "stacked": False, "align": "edge"}, | ||||
|             {"kind": "bar", "stacked": False, "width": 0.9, "align": "edge"}, | ||||
|             {"kind": "barh", "stacked": False, "align": "edge"}, | ||||
|             {"kind": "barh", "stacked": False, "width": 0.9, "align": "edge"}, | ||||
|             {"kind": "bar", "subplots": True, "align": "edge"}, | ||||
|             {"kind": "bar", "subplots": True, "width": 0.9, "align": "edge"}, | ||||
|             {"kind": "barh", "subplots": True, "align": "edge"}, | ||||
|             {"kind": "barh", "subplots": True, "width": 0.9, "align": "edge"}, | ||||
|         ], | ||||
|     ) | ||||
|     def test_bar_align_multiple_columns(self, kwargs): | ||||
|         # GH2157 | ||||
|         df = DataFrame({"A": [3] * 5, "B": list(range(5))}, index=range(5)) | ||||
|         self._check_bar_alignment(df, **kwargs) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kwargs", | ||||
|         [ | ||||
|             {"kind": "bar", "stacked": False}, | ||||
|             {"kind": "bar", "stacked": True}, | ||||
|             {"kind": "barh", "stacked": False}, | ||||
|             {"kind": "barh", "stacked": True}, | ||||
|             {"kind": "bar", "subplots": True}, | ||||
|             {"kind": "barh", "subplots": True}, | ||||
|         ], | ||||
|     ) | ||||
|     def test_bar_align_single_column(self, kwargs): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal(5)) | ||||
|         self._check_bar_alignment(df, **kwargs) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kwargs", | ||||
|         [ | ||||
|             {"kind": "bar", "stacked": False}, | ||||
|             {"kind": "bar", "stacked": True}, | ||||
|             {"kind": "barh", "stacked": False}, | ||||
|             {"kind": "barh", "stacked": True}, | ||||
|             {"kind": "bar", "subplots": True}, | ||||
|             {"kind": "barh", "subplots": True}, | ||||
|         ], | ||||
|     ) | ||||
|     def test_bar_barwidth_position(self, kwargs): | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         self._check_bar_alignment(df, width=0.9, position=0.2, **kwargs) | ||||
|  | ||||
|     @pytest.mark.parametrize("w", [1, 1.0]) | ||||
|     def test_bar_barwidth_position_int(self, w): | ||||
|         # GH 12979 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         ax = df.plot.bar(stacked=True, width=w) | ||||
|         ticks = ax.xaxis.get_ticklocs() | ||||
|         tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4])) | ||||
|         assert ax.get_xlim() == (-0.75, 4.75) | ||||
|         # check left-edge of bars | ||||
|         assert ax.patches[0].get_x() == -0.5 | ||||
|         assert ax.patches[-1].get_x() == 3.5 | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "kind, kwargs", | ||||
|         [ | ||||
|             ["bar", {"stacked": True}], | ||||
|             ["barh", {"stacked": False}], | ||||
|             ["barh", {"stacked": True}], | ||||
|             ["bar", {"subplots": True}], | ||||
|             ["barh", {"subplots": True}], | ||||
|         ], | ||||
|     ) | ||||
|     def test_bar_barwidth_position_int_width_1(self, kind, kwargs): | ||||
|         # GH 12979 | ||||
|         df = DataFrame(np.random.default_rng(2).standard_normal((5, 5))) | ||||
|         self._check_bar_alignment(df, kind=kind, width=1, **kwargs) | ||||
|  | ||||
|     def _check_bar_alignment( | ||||
|         self, | ||||
|         df, | ||||
|         kind="bar", | ||||
|         stacked=False, | ||||
|         subplots=False, | ||||
|         align="center", | ||||
|         width=0.5, | ||||
|         position=0.5, | ||||
|     ): | ||||
|         axes = df.plot( | ||||
|             kind=kind, | ||||
|             stacked=stacked, | ||||
|             subplots=subplots, | ||||
|             align=align, | ||||
|             width=width, | ||||
|             position=position, | ||||
|             grid=True, | ||||
|         ) | ||||
|  | ||||
|         axes = _flatten_visible(axes) | ||||
|  | ||||
|         for ax in axes: | ||||
|             if kind == "bar": | ||||
|                 axis = ax.xaxis | ||||
|                 ax_min, ax_max = ax.get_xlim() | ||||
|                 min_edge = min(p.get_x() for p in ax.patches) | ||||
|                 max_edge = max(p.get_x() + p.get_width() for p in ax.patches) | ||||
|             elif kind == "barh": | ||||
|                 axis = ax.yaxis | ||||
|                 ax_min, ax_max = ax.get_ylim() | ||||
|                 min_edge = min(p.get_y() for p in ax.patches) | ||||
|                 max_edge = max(p.get_y() + p.get_height() for p in ax.patches) | ||||
|             else: | ||||
|                 raise ValueError | ||||
|  | ||||
|             # GH 7498 | ||||
|             # compare margins between lim and bar edges | ||||
|             tm.assert_almost_equal(ax_min, min_edge - 0.25) | ||||
|             tm.assert_almost_equal(ax_max, max_edge + 0.25) | ||||
|  | ||||
|             p = ax.patches[0] | ||||
|             if kind == "bar" and (stacked is True or subplots is True): | ||||
|                 edge = p.get_x() | ||||
|                 center = edge + p.get_width() * position | ||||
|             elif kind == "bar" and stacked is False: | ||||
|                 center = p.get_x() + p.get_width() * len(df.columns) * position | ||||
|                 edge = p.get_x() | ||||
|             elif kind == "barh" and (stacked is True or subplots is True): | ||||
|                 center = p.get_y() + p.get_height() * position | ||||
|                 edge = p.get_y() | ||||
|             elif kind == "barh" and stacked is False: | ||||
|                 center = p.get_y() + p.get_height() * len(df.columns) * position | ||||
|                 edge = p.get_y() | ||||
|             else: | ||||
|                 raise ValueError | ||||
|  | ||||
|             # Check the ticks locates on integer | ||||
|             assert (axis.get_ticklocs() == np.arange(len(df))).all() | ||||
|  | ||||
|             if align == "center": | ||||
|                 # Check whether the bar locates on center | ||||
|                 tm.assert_almost_equal(axis.get_ticklocs()[0], center) | ||||
|             elif align == "edge": | ||||
|                 # Check whether the bar's edge starts from the tick | ||||
|                 tm.assert_almost_equal(axis.get_ticklocs()[0], edge) | ||||
|             else: | ||||
|                 raise ValueError | ||||
|  | ||||
|         return axes | ||||
| @ -0,0 +1,342 @@ | ||||
| import re | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import DataFrame | ||||
| import pandas._testing as tm | ||||
| from pandas.tests.plotting.common import ( | ||||
|     _check_axes_shape, | ||||
|     _check_plot_works, | ||||
|     get_x_axis, | ||||
|     get_y_axis, | ||||
| ) | ||||
|  | ||||
| pytest.importorskip("matplotlib") | ||||
|  | ||||
|  | ||||
| @pytest.fixture | ||||
| def hist_df(): | ||||
|     df = DataFrame( | ||||
|         np.random.default_rng(2).standard_normal((30, 2)), columns=["A", "B"] | ||||
|     ) | ||||
|     df["C"] = np.random.default_rng(2).choice(["a", "b", "c"], 30) | ||||
|     df["D"] = np.random.default_rng(2).choice(["a", "b", "c"], 30) | ||||
|     return df | ||||
|  | ||||
|  | ||||
| class TestHistWithBy: | ||||
|     @pytest.mark.slow | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column, titles, legends", | ||||
|         [ | ||||
|             ("C", "A", ["a", "b", "c"], [["A"]] * 3), | ||||
|             ("C", ["A", "B"], ["a", "b", "c"], [["A", "B"]] * 3), | ||||
|             ("C", None, ["a", "b", "c"], [["A", "B"]] * 3), | ||||
|             ( | ||||
|                 ["C", "D"], | ||||
|                 "A", | ||||
|                 [ | ||||
|                     "(a, a)", | ||||
|                     "(b, b)", | ||||
|                     "(c, c)", | ||||
|                 ], | ||||
|                 [["A"]] * 3, | ||||
|             ), | ||||
|             ( | ||||
|                 ["C", "D"], | ||||
|                 ["A", "B"], | ||||
|                 [ | ||||
|                     "(a, a)", | ||||
|                     "(b, b)", | ||||
|                     "(c, c)", | ||||
|                 ], | ||||
|                 [["A", "B"]] * 3, | ||||
|             ), | ||||
|             ( | ||||
|                 ["C", "D"], | ||||
|                 None, | ||||
|                 [ | ||||
|                     "(a, a)", | ||||
|                     "(b, b)", | ||||
|                     "(c, c)", | ||||
|                 ], | ||||
|                 [["A", "B"]] * 3, | ||||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     def test_hist_plot_by_argument(self, by, column, titles, legends, hist_df): | ||||
|         # GH 15079 | ||||
|         axes = _check_plot_works( | ||||
|             hist_df.plot.hist, column=column, by=by, default_axes=True | ||||
|         ) | ||||
|         result_titles = [ax.get_title() for ax in axes] | ||||
|         result_legends = [ | ||||
|             [legend.get_text() for legend in ax.get_legend().texts] for ax in axes | ||||
|         ] | ||||
|  | ||||
|         assert result_legends == legends | ||||
|         assert result_titles == titles | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column, titles, legends", | ||||
|         [ | ||||
|             (0, "A", ["a", "b", "c"], [["A"]] * 3), | ||||
|             (0, None, ["a", "b", "c"], [["A", "B"]] * 3), | ||||
|             ( | ||||
|                 [0, "D"], | ||||
|                 "A", | ||||
|                 [ | ||||
|                     "(a, a)", | ||||
|                     "(b, b)", | ||||
|                     "(c, c)", | ||||
|                 ], | ||||
|                 [["A"]] * 3, | ||||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     def test_hist_plot_by_0(self, by, column, titles, legends, hist_df): | ||||
|         # GH 15079 | ||||
|         df = hist_df.copy() | ||||
|         df = df.rename(columns={"C": 0}) | ||||
|  | ||||
|         axes = _check_plot_works(df.plot.hist, default_axes=True, column=column, by=by) | ||||
|         result_titles = [ax.get_title() for ax in axes] | ||||
|         result_legends = [ | ||||
|             [legend.get_text() for legend in ax.get_legend().texts] for ax in axes | ||||
|         ] | ||||
|  | ||||
|         assert result_legends == legends | ||||
|         assert result_titles == titles | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column", | ||||
|         [ | ||||
|             ([], ["A"]), | ||||
|             ([], ["A", "B"]), | ||||
|             ((), None), | ||||
|             ((), ["A", "B"]), | ||||
|         ], | ||||
|     ) | ||||
|     def test_hist_plot_empty_list_string_tuple_by(self, by, column, hist_df): | ||||
|         # GH 15079 | ||||
|         msg = "No group keys passed" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             _check_plot_works( | ||||
|                 hist_df.plot.hist, default_axes=True, column=column, by=by | ||||
|             ) | ||||
|  | ||||
|     @pytest.mark.slow | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column, layout, axes_num", | ||||
|         [ | ||||
|             (["C"], "A", (2, 2), 3), | ||||
|             ("C", "A", (2, 2), 3), | ||||
|             (["C"], ["A"], (1, 3), 3), | ||||
|             ("C", None, (3, 1), 3), | ||||
|             ("C", ["A", "B"], (3, 1), 3), | ||||
|             (["C", "D"], "A", (9, 1), 3), | ||||
|             (["C", "D"], "A", (3, 3), 3), | ||||
|             (["C", "D"], ["A"], (5, 2), 3), | ||||
|             (["C", "D"], ["A", "B"], (9, 1), 3), | ||||
|             (["C", "D"], None, (9, 1), 3), | ||||
|             (["C", "D"], ["A", "B"], (5, 2), 3), | ||||
|         ], | ||||
|     ) | ||||
|     def test_hist_plot_layout_with_by(self, by, column, layout, axes_num, hist_df): | ||||
|         # GH 15079 | ||||
|         # _check_plot_works adds an ax so catch warning. see GH #13188 | ||||
|         with tm.assert_produces_warning(UserWarning, check_stacklevel=False): | ||||
|             axes = _check_plot_works( | ||||
|                 hist_df.plot.hist, column=column, by=by, layout=layout | ||||
|             ) | ||||
|         _check_axes_shape(axes, axes_num=axes_num, layout=layout) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "msg, by, layout", | ||||
|         [ | ||||
|             ("larger than required size", ["C", "D"], (1, 1)), | ||||
|             (re.escape("Layout must be a tuple of (rows, columns)"), "C", (1,)), | ||||
|             ("At least one dimension of layout must be positive", "C", (-1, -1)), | ||||
|         ], | ||||
|     ) | ||||
|     def test_hist_plot_invalid_layout_with_by_raises(self, msg, by, layout, hist_df): | ||||
|         # GH 15079, test if error is raised when invalid layout is given | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             hist_df.plot.hist(column=["A", "B"], by=by, layout=layout) | ||||
|  | ||||
|     @pytest.mark.slow | ||||
|     def test_axis_share_x_with_by(self, hist_df): | ||||
|         # GH 15079 | ||||
|         ax1, ax2, ax3 = hist_df.plot.hist(column="A", by="C", sharex=True) | ||||
|  | ||||
|         # share x | ||||
|         assert get_x_axis(ax1).joined(ax1, ax2) | ||||
|         assert get_x_axis(ax2).joined(ax1, ax2) | ||||
|         assert get_x_axis(ax3).joined(ax1, ax3) | ||||
|         assert get_x_axis(ax3).joined(ax2, ax3) | ||||
|  | ||||
|         # don't share y | ||||
|         assert not get_y_axis(ax1).joined(ax1, ax2) | ||||
|         assert not get_y_axis(ax2).joined(ax1, ax2) | ||||
|         assert not get_y_axis(ax3).joined(ax1, ax3) | ||||
|         assert not get_y_axis(ax3).joined(ax2, ax3) | ||||
|  | ||||
|     @pytest.mark.slow | ||||
|     def test_axis_share_y_with_by(self, hist_df): | ||||
|         # GH 15079 | ||||
|         ax1, ax2, ax3 = hist_df.plot.hist(column="A", by="C", sharey=True) | ||||
|  | ||||
|         # share y | ||||
|         assert get_y_axis(ax1).joined(ax1, ax2) | ||||
|         assert get_y_axis(ax2).joined(ax1, ax2) | ||||
|         assert get_y_axis(ax3).joined(ax1, ax3) | ||||
|         assert get_y_axis(ax3).joined(ax2, ax3) | ||||
|  | ||||
|         # don't share x | ||||
|         assert not get_x_axis(ax1).joined(ax1, ax2) | ||||
|         assert not get_x_axis(ax2).joined(ax1, ax2) | ||||
|         assert not get_x_axis(ax3).joined(ax1, ax3) | ||||
|         assert not get_x_axis(ax3).joined(ax2, ax3) | ||||
|  | ||||
|     @pytest.mark.parametrize("figsize", [(12, 8), (20, 10)]) | ||||
|     def test_figure_shape_hist_with_by(self, figsize, hist_df): | ||||
|         # GH 15079 | ||||
|         axes = hist_df.plot.hist(column="A", by="C", figsize=figsize) | ||||
|         _check_axes_shape(axes, axes_num=3, figsize=figsize) | ||||
|  | ||||
|  | ||||
| class TestBoxWithBy: | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column, titles, xticklabels", | ||||
|         [ | ||||
|             ("C", "A", ["A"], [["a", "b", "c"]]), | ||||
|             ( | ||||
|                 ["C", "D"], | ||||
|                 "A", | ||||
|                 ["A"], | ||||
|                 [ | ||||
|                     [ | ||||
|                         "(a, a)", | ||||
|                         "(b, b)", | ||||
|                         "(c, c)", | ||||
|                     ] | ||||
|                 ], | ||||
|             ), | ||||
|             ("C", ["A", "B"], ["A", "B"], [["a", "b", "c"]] * 2), | ||||
|             ( | ||||
|                 ["C", "D"], | ||||
|                 ["A", "B"], | ||||
|                 ["A", "B"], | ||||
|                 [ | ||||
|                     [ | ||||
|                         "(a, a)", | ||||
|                         "(b, b)", | ||||
|                         "(c, c)", | ||||
|                     ] | ||||
|                 ] | ||||
|                 * 2, | ||||
|             ), | ||||
|             (["C"], None, ["A", "B"], [["a", "b", "c"]] * 2), | ||||
|         ], | ||||
|     ) | ||||
|     def test_box_plot_by_argument(self, by, column, titles, xticklabels, hist_df): | ||||
|         # GH 15079 | ||||
|         axes = _check_plot_works( | ||||
|             hist_df.plot.box, default_axes=True, column=column, by=by | ||||
|         ) | ||||
|         result_titles = [ax.get_title() for ax in axes] | ||||
|         result_xticklabels = [ | ||||
|             [label.get_text() for label in ax.get_xticklabels()] for ax in axes | ||||
|         ] | ||||
|  | ||||
|         assert result_xticklabels == xticklabels | ||||
|         assert result_titles == titles | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column, titles, xticklabels", | ||||
|         [ | ||||
|             (0, "A", ["A"], [["a", "b", "c"]]), | ||||
|             ( | ||||
|                 [0, "D"], | ||||
|                 "A", | ||||
|                 ["A"], | ||||
|                 [ | ||||
|                     [ | ||||
|                         "(a, a)", | ||||
|                         "(b, b)", | ||||
|                         "(c, c)", | ||||
|                     ] | ||||
|                 ], | ||||
|             ), | ||||
|             (0, None, ["A", "B"], [["a", "b", "c"]] * 2), | ||||
|         ], | ||||
|     ) | ||||
|     def test_box_plot_by_0(self, by, column, titles, xticklabels, hist_df): | ||||
|         # GH 15079 | ||||
|         df = hist_df.copy() | ||||
|         df = df.rename(columns={"C": 0}) | ||||
|  | ||||
|         axes = _check_plot_works(df.plot.box, default_axes=True, column=column, by=by) | ||||
|         result_titles = [ax.get_title() for ax in axes] | ||||
|         result_xticklabels = [ | ||||
|             [label.get_text() for label in ax.get_xticklabels()] for ax in axes | ||||
|         ] | ||||
|  | ||||
|         assert result_xticklabels == xticklabels | ||||
|         assert result_titles == titles | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column", | ||||
|         [ | ||||
|             ([], ["A"]), | ||||
|             ((), "A"), | ||||
|             ([], None), | ||||
|             ((), ["A", "B"]), | ||||
|         ], | ||||
|     ) | ||||
|     def test_box_plot_with_none_empty_list_by(self, by, column, hist_df): | ||||
|         # GH 15079 | ||||
|         msg = "No group keys passed" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             _check_plot_works(hist_df.plot.box, default_axes=True, column=column, by=by) | ||||
|  | ||||
|     @pytest.mark.slow | ||||
|     @pytest.mark.parametrize( | ||||
|         "by, column, layout, axes_num", | ||||
|         [ | ||||
|             (["C"], "A", (1, 1), 1), | ||||
|             ("C", "A", (1, 1), 1), | ||||
|             ("C", None, (2, 1), 2), | ||||
|             ("C", ["A", "B"], (1, 2), 2), | ||||
|             (["C", "D"], "A", (1, 1), 1), | ||||
|             (["C", "D"], None, (1, 2), 2), | ||||
|         ], | ||||
|     ) | ||||
|     def test_box_plot_layout_with_by(self, by, column, layout, axes_num, hist_df): | ||||
|         # GH 15079 | ||||
|         axes = _check_plot_works( | ||||
|             hist_df.plot.box, default_axes=True, column=column, by=by, layout=layout | ||||
|         ) | ||||
|         _check_axes_shape(axes, axes_num=axes_num, layout=layout) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "msg, by, layout", | ||||
|         [ | ||||
|             ("larger than required size", ["C", "D"], (1, 1)), | ||||
|             (re.escape("Layout must be a tuple of (rows, columns)"), "C", (1,)), | ||||
|             ("At least one dimension of layout must be positive", "C", (-1, -1)), | ||||
|         ], | ||||
|     ) | ||||
|     def test_box_plot_invalid_layout_with_by_raises(self, msg, by, layout, hist_df): | ||||
|         # GH 15079, test if error is raised when invalid layout is given | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             hist_df.plot.box(column=["A", "B"], by=by, layout=layout) | ||||
|  | ||||
|     @pytest.mark.parametrize("figsize", [(12, 8), (20, 10)]) | ||||
|     def test_figure_shape_hist_with_by(self, figsize, hist_df): | ||||
|         # GH 15079 | ||||
|         axes = hist_df.plot.box(column="A", by="C", figsize=figsize) | ||||
|         _check_axes_shape(axes, axes_num=1, figsize=figsize) | ||||
		Reference in New Issue
	
	Block a user