【问题标题】:How to get colors of pandas bar plot如何获得熊猫条形图的颜色
【发布时间】:2021-11-10 09:22:21
【问题描述】:

如何获取 pandas 条形图中元素的颜色?

示例:我有一个包含几列历史数据的条形图。现在我想用与条形相同颜色的每列的平均值绘制一条水平线。

这个问题讨论了对 matplotlib 线图颜色的访问:How to get color of most recent plotted line in Python's plt

它允许我获得线图的颜色,但不能获得条形图的颜色。我想可能有一个等价于get_lines(),但我找不到它。

"""Access bar plot colors."""

import pandas as pd
df = pd.DataFrame(data={'col1': [1, 2], 'col2': [3, 4]})
ax = df.plot()

# This works fine for line plots
for i, col in enumerate(df):
    color = ax.get_lines()[i].get_color()
    print(color)


ax = df.plot(kind='bar')

# This does not work: "IndexError: list index out of range"
for i, col in enumerate(df):
    color = ax.get_lines()[i].get_color()
    print(color)

【问题讨论】:

标签: python pandas matplotlib


【解决方案1】:

你可以使用.patches:

>>> ax = df.plot(kind='bar')
>>> print(ax.patches)
[<matplotlib.patches.Rectangle object at 0x7f02e2ba3760>, <matplotlib.patches.Rectangle object at 0x7f02e2ba35e0>, <matplotlib.patches.Rectangle object at 0x7f02e2ba3dc0>, <matplotlib.patches.Rectangle object at 0x7f02e2ba35b0>]
>>> for i, col in enumerate(df):
...     color = ax.patches[i].get_facecolor()
...     print(color)
...
(0.12156862745098039, 0.4666666666666667, 0.7058823529411765, 1.0)
(0.12156862745098039, 0.4666666666666667, 0.7058823529411765, 1.0)

但是,如您所见,枚举它们并不能告诉您哪个补丁对应于哪个数据。在这里,我们抓取了 2 个相同颜色的矩形。因此,我会推荐用于构建图例的.get_legend_handles_labels() 函数:

>>> print(ax.get_legend_handles_labels())
([<BarContainer object of 2 artists>, <BarContainer object of 2 artists>], ['col1', 'col2'])
>>> for bars, column in zip(*ax.get_legend_handles_labels()):
...     color = bars[0].get_facecolor()
...     print(column, color)
...
col1 (0.12156862745098039, 0.4666666666666667, 0.7058823529411765, 1.0)
col2 (1.0, 0.4980392156862745, 0.054901960784313725, 1.0)

【讨论】:

    【解决方案2】:

    我会改变它并自己明确地绘制数据,而不是试图从返回的轴中拼出你需要的东西。但 Cimbali 已经展示了您如何在需要时做到这一点。

    代码有点多,但是自己调用ax.bar可以让你捕获返回值。

    例如绘图:

    fig, ax = plt.subplots()
    
    idx = df.index.values
    
    width = 0.25
    col1_bars = ax.bar(idx - width/2, 'col1', width, label='Col1', data=df)
    col2_bars = ax.bar(idx + width/2, 'col2', width, label='Col2', data=df)
    
    ax.set_xticks(idx)
    ax.legend(loc=2)
    

    然后,您可以通过检查返回的 BarContainer 对象来提取颜色或条形的任何其他属性:

    col1_colors = list(map(lambda x: x.get_facecolor(), col1_bars))
    col2_colors = list(map(lambda x: x.get_facecolor(), col2_bars))
    

    【讨论】:

    • 我必须说无论如何我通常都会为时间序列执行此操作,因为 pandas 在 x 轴上自动显示时间过去非常垃圾(坦率地说仍然有点笨拙)。如果您想更好地控制您的绘图,这是更好的方法。
    • 是的,我也是。 Pandas 的内置绘图方法(以及许多其他软件包,如 Xarray 等)非常适合快速探索,但我通常发现自己最终会在需要花哨的时候使用“裸”Matplotlib。
    【解决方案3】:

    结合 Rutger 和 Cimbali 的答案,我想出了自己的解决方案,我将其留在这里以供参考:可以找到正确的 BarContainer 并以这种方式获得颜色。但是 Cimbali 对 get_legend_handles_labels() 的使用可能更优雅。 :-)

    """Access bar plot colors."""
    
    import pandas as pd
    import matplotlib.pyplot as plt
    
    df = pd.DataFrame(data={'col1': [1, 2], 'col2': [3, 4]})
    
    # This works fine for line plots
    ax = df.plot()
    for i, col in enumerate(df):
        color = ax.get_lines()[i].get_color()
        print(color)
        ax.axhline(y=df[col].mean(), label=col+' (mean)', linestyle='--', c=color)
    plt.legend()
    plt.show()
    
    # Now try with bar plot: Access color via BarContainer
    ax = df.plot(kind='bar')
    for i, col in enumerate(df):
        color = ax.containers[i][0].get_facecolor()
        ax.axhline(y=df[col].mean(), label=col+' (mean)', linestyle='--', c=color)
    plt.legend()
    plt.show()
    
    # Now try with bar plot: Access color via get_legend_handles_labels()
    ax = df.plot(kind='bar')
    for bars, col in zip(*ax.get_legend_handles_labels()):
        color = bars[0].get_facecolor()
        ax.axhline(y=df[col].mean(), label=col+' (mean)', linestyle='--', c=color)
    plt.legend()
    plt.show()
    
    

    【讨论】:

      猜你喜欢
      • 2019-05-17
      • 1970-01-01
      • 2017-12-30
      • 2021-08-14
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      相关资源
      最近更新 更多