Updated script that can be controled by Nodejs web app
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