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

Posted

技术标签:

【中文标题】熊猫箱线图中每个子图的独立轴【英文标题】:Independent axis for each subplot in pandas boxplot 【发布时间】:2018-11-30 22:29:32 【问题描述】:

下面的代码有助于获得带有独特颜色框的子图。但所有子图共享一组共同的 x 和 y 轴。我期待每个子图都有独立的轴:

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=(2,2),figsize=(6,4),
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()

这是上述代码的输出:

我正在尝试为每个子图设置单独的 x 轴和 y 轴...

【问题讨论】:

【参考方案1】:

您需要事先创建图形和子图,并将其作为参数传递给df.boxplot()。这也意味着您可以删除参数layout=(2,2)

fig, axes = plt.subplots(2,2,sharex=False,sharey=False)

然后使用:

bp_dict = df.boxplot(
by="models", ax=axes, figsize=(6,4),
return_type='both',
patch_artist = True,
)

【讨论】:

感谢您的回答...将布局限制为 plt.subplots 要求网格框的数量等于所需的子图。你能建议一种相对简单的方法来容纳 2xn 布局中的 13 个子图吗?如果我在 df.boxplot 中使用布局参数,那么轴保持共享..【参考方案2】:

您可以将刻度标签重新设置为可见,例如通过

plt.setp(ax.get_xticklabels(), visible=True)

虽然这不会使轴独立,但它们仍然相互绑定,但您似乎在询问可见性,而不是此处的共享行为。

【讨论】:

感谢您的回答..但我的意思是为所有轴设置具有独立范围的独立轴(尤其是 ylims 需要为每个子图分开的 y 轴)。边界范围会抑制数据范围较低但轴范围较高的框的视图。 在这种情况下,请参阅其他答案。【参考方案3】:

如果您真的认为有必要在创建boxplot 数组之后取消共享轴,您可以这样做,但您必须“手动”完成所有操作。通过***搜索一段时间并查看matplotlib文档页面,我想出了以下解决方案来取消共享Axes实例的yaxes,对于xaxes,您必须进行类似的操作:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
from matplotlib.ticker import AutoLocator, AutoMinorLocator

##using differently scaled data for the different random series:
df = pd.DataFrame(
    np.asarray([
        np.random.rand(140),
        2*np.random.rand(140),
        4*np.random.rand(140),
        8*np.random.rand(140),
    ]).T,
    columns=['A', 'B', 'C', 'D']
)

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

##creating the boxplot array:
bp_dict = df.boxplot(
    by="models",layout = (2,2),figsize=(6,8),
    return_type='both',
    patch_artist = True,
    rot = 45,
)

colors = ['b', 'y', 'm', 'c', 'g', 'b', 'r', 'k', ]

##adjusting the Axes instances to your needs
for row_key, (ax,row) in bp_dict.items():
    ax.set_xlabel('')

    ##removing shared axes:
    grouper = ax.get_shared_y_axes()
    shared_ys = [a for a in grouper]
    for ax_list in shared_ys:
        for ax2 in ax_list:
            grouper.remove(ax2)

    ##setting limits:
    ax.axis('auto')
    ax.relim()      #<-- maybe not necessary

    ##adjusting tick positions:
    ax.yaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_minor_locator(AutoMinorLocator())

    ##making tick labels visible:    
    plt.setp(ax.get_yticklabels(), visible=True)

    for i,box in enumerate(row['boxes']):
        box.set_facecolor(colors[i])

plt.show()

生成的图如下所示:

解释

您首先需要告诉每个Axes 实例它不应与任何其他Axis 实例共享其yaxis。 This post 让我了解了如何做到这一点——Axes.get_shared_y_axes() 返回一个Grouper object,它包含对所有其他Axes 实例的引用,当前Axes 应该与之共享其xaxis。循环遍历这些实例并调用 Grouper.remove 会执行实际的取消共享。

yaxis 取消共享后,y 限制和 y 刻度需要调整。前者可以通过ax.axis('auto')ax.relim() 实现(不确定是否需要第二条命令)。可以使用ax.yaxis.set_major_locator()ax.yaxis.set_minor_locator() 以及适当的Locators 来调整刻度。最后,可以使用plt.setp(ax.get_yticklabels(), visible=True) (see here) 使刻度标签可见。

考虑到这一切,我认为@DavidG 的answer 是更好的方法。

【讨论】:

以上是关于熊猫箱线图中每个子图的独立轴的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

更改熊猫中箱线图的面色

使用熊猫的箱线图

时间序列 Python 中每小时数据的箱线图