更改熊猫箱线图子图中各个框的颜色

Posted

技术标签:

【中文标题】更改熊猫箱线图子图中各个框的颜色【英文标题】:Change color of individual boxes in pandas boxplot subplots 【发布时间】:2018-11-30 12:23:24 【问题描述】:

这是参考以下问题,其中讨论了调整子图标题和布局的选项: modify pandas boxplot output

我的要求是更改每个子图中各个框的颜色(如下所示):

以下是共享链接中用于调整子图的标题和轴属性的代码:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.rand(140, 4), columns=['A', 'B', 'C', 'D'])
df['models'] = pd.Series(np.repeat(['model1','model2', 'model3', 'model4',     'model5', 'model6', 'model7'], 20))
bp = df.boxplot(by="models",layout=(4,1),figsize=(6,8))
[ax_tmp.set_xlabel('') for ax_tmp in np.asarray(bp).reshape(-1)]
fig = np.asarray(bp).reshape(-1)[0].get_figure()
fig.suptitle('New title here')
plt.show()

我尝试使用: ax.set_facecolor('颜色') 属性,但没有成功获得想要的结果。

我也尝试访问 bp['boxes'] 但显然它不可用。我需要了解存储在 bp 中的数据结构,才能访问子图中的各个框。

期待

P.S:我知道 seaborn。但目前需要使用 df.boxplot 来理解和实现。谢谢

【问题讨论】:

我认为使用 pandas 很难做到这一点。由于 pandas 绘图在引擎盖下使用 matplotlib,我会考虑使用纯 matplotlib,这使得更改单个框的颜色变得非常容易 【参考方案1】:

要调整 pandas.boxplot 中框的颜色,您必须稍微调整代码。首先,您必须告诉boxplot 实际用颜色填充框。您可以通过指定patch_artist = True 来执行此操作,如文档中的here 所述。但是,您似乎无法指定颜色(默认为蓝色) - 如果我错了,请任何人纠正我。这意味着您必须在之后更改颜色。幸运的是,pandas.boxplot 提供了一个简单的选项,通过指定 return_type = 'both' see here 来获取箱线图中的艺术家作为返回值进行解释。你得到的是一个pandas.Series,其中的键根据你的DataFrame 列和值是包含绘制箱线图的Axes 实例的元组以及字典中箱线图的实际元素。我认为代码是不言自明的:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch

df = pd.DataFrame(np.random.rand(140, 4), columns=['A', 'B', 'C', 'D'])

df['models'] = pd.Series(np.repeat(['model1','model2', 'model3', 'model4',     'model5', 'model6', 'model7'], 20))

bp_dict = df.boxplot(
    by="models",layout=(4,1),figsize=(6,8),
    return_type='both',
    patch_artist = True,
)

colors = ['b', 'y', 'm', 'c', 'g', 'b', 'r', 'k', ]
for row_key, (ax,row) in bp_dict.iteritems():
    ax.set_xlabel('')
    for i,box in enumerate(row['boxes']):
        box.set_facecolor(colors[i])

plt.show()

生成的图如下所示:

希望这会有所帮助。

【讨论】:

谢谢 Thomas :) 这很有帮助。只是提到我最终使用了 bp_dict.iteritems(): 因为我收到了属性错误 - “AttributeError: 'Series' object has no attribute 'items'” 嗨 Thomas。如何为每个子图保留独立轴(y 和 x)?我用 i,el in enumerate(list(df.columns.values)): df.boxplot(el, by=metacategory,ax=axes.flatten()[i]) 但无法将独立颜色应用于在那种情况下每个盒子...... ***.com/questions/50971091/… @JALO-JusAnotherLivngOrganism 感谢您的评论——我稍微编辑了答案。我也会看看你的其他问题......【参考方案2】:

虽然你将返回命名为df.boxplotbp,但它实际上是一个(n)个(数组)轴。检查轴以获取箱线图的各个部分很麻烦(但可能)。

首先,为了能够为盒子的内部着色,您需要将盒子变成补丁,df.boxplot(..., patch_artist=True)

然后您需要在坐标轴中的所有艺术家中找到框。

# We want to make the 4th box in the second axes red    
axes[1].findobj(matplotlib.patches.Patch)[3].set_facecolor("red")

完整代码:

import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.rand(140, 4), columns=['A', 'B', 'C', 'D'])
df['models'] = pd.Series(np.repeat(['model1', 'model2', 'model3', 'model4',
                                    'model5', 'model6', 'model7'], 20))
axes = df.boxplot(by="models", layout=(len(df.columns)-1,1), figsize=(6,8), patch_artist=True)

for ax in axes:
    ax.set_xlabel('')

# We want to make the 4th box in the second axes red    
axes[1].findobj(matplotlib.patches.Patch)[3].set_facecolor("red")

fig = axes[0].get_figure()
fig.suptitle('New title here')
plt.show()

【讨论】:

非常感谢您的意见 :) 您的回答确实帮助我更好地理解了结构。你的两个答案都很有帮助和完美。我接受托马斯的回答只是为了尊重他首先回答的事实。我希望有接受这两个选项..再次非常感谢。顺便说一句,我仍在学习过程中,关于如何独立追求变量/赋值结构的任何建议?以便了解需要哪些索引?再次感谢。问候 JALO 哦,我没有看到其他答案。这可能是更好的一个,因为您不必在轴中找到对象(如果您在轴中还有其他绘图对象,这也是相关的)。不知道我理解你所说的“独立地追求变量/赋值的结构”是什么意思。 我的意思是如何在坐标区中查找对象。例如,作为一个新手,我试图打印轴。我试图为每个子图手动分配 y 轴的限制(一行中的子图共享公共 y 轴/x 轴)。我正在使用 ymx=max(df.loc[row_key]); ax.set_ylim(0, ymx),但我认为有一个命令可以保持轴分开? for i,el in enumerate(list(df.columns.values)[:-1]): tt.boxplot(el, by=metacategory,ax=axes.flatten()[i]) 有帮助,但我不能以这种方式为各个框着色...findobj 不存在用于子图.. 我认为您正在尝试将一个完整的问题压缩成 300 个字符的评论。我不认为我以这种压缩方式理解你的问题。 这里是问题:***.com/questions/50971091/…

以上是关于更改熊猫箱线图子图中各个框的颜色的主要内容,如果未能解决你的问题,请参考以下文章

熊猫箱线图中每个子图的独立轴

向熊猫数据框箱线图添加标签?

为熊猫箱线图(groupby)设置无标题

Matplotlib 箱线图 x 轴

如何按中值对熊猫中的箱线图进行排序?

使用熊猫的箱线图