首页 > 解决方案 > 如何修复 matplotlib 中所有子图的图例和主标题?

问题描述

我是 Python 新手,我一直在使用虚拟数据集来练习 Python。以前我在生成子图、然后绘制频率和比例 % 时遇到了麻烦,但现在我今天已经克服了它们。现在,我正在努力修复一些化妆品,尤其是传说和情节标题。

这是生成整个虚拟数据集的可重现代码:

d = {
    'SeniorCitizen': [0,1,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0] , 
    'CollegeDegree': [0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1] , 
    'Married': [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1] , 
    'FulltimeJob': [1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,0,1] , 
    'DistancefromBranch': [7,9,14,20,21,12,22,25,9,9,9,12,13,14,16,25,27,4,14,14,20,19,15,23,2] , 
    'ReversedPayment': [0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0] }
CarWash = pd.DataFrame(data = d)


categoricals = ['SeniorCitizen','CollegeDegree','Married','FulltimeJob','ReversedPayment']
        numerical = ['DistancefromBranch']
CarWash[categoricals] = CarWash[categoricals].astype('category')

下面是我尝试生成频率和比例 %,以进行并排比较:

plt.suptitle("Distribution of target variable across the categorical variables - frequencies # and proportions %")

nrow = 1
ncol = len(categoricals[:-1])
figure, axes = plt.subplots(nrow,ncol, figsize = (40,10))
for i,ax in zip(categoricals[:-1],axes.flatten()):
    
    # plots frequencies
    CarWash.groupby([i,'ReversedPayment']).size().reset_index().pivot(index = i,columns = 'ReversedPayment').plot(kind = 'bar', stacked = True, ax = ax, sharey=True)
    ax.tick_params(axis='both', labelsize = 25, labelrotation = 0)   
    ax.set_title(i,fontsize = 30)
    ax.set_xlabel("")
    #ax.get_legend().remove()
    # labels data
    for p in ax.patches:       
        x_adjust = 0.25
        
        value = p.get_height()
        X = p.get_x() + x_adjust
        Y = p.get_y() + p.get_height()/2
        
        XY = (X,Y)
        if value != 0:
            ax.annotate(int(value),XY,fontsize = 25)


nrow = 1
ncol = len(categoricals[:-1])
figure, axes = plt.subplots(nrow,ncol, figsize = (40,10))
for i,ax in zip(categoricals[:-1],axes.flatten()):
    
    # plots proportions    
    CarWash.groupby([i,'ReversedPayment']).size().reset_index().pivot(index = i, columns = 'ReversedPayment').apply(lambda x: x/x.sum(),axis=1).plot(kind = 'bar', stacked = True, ax = ax)
    ax.tick_params(axis='both', labelsize = 25, labelrotation = 0)   
    ax.set_title(i,fontsize = 30)
    ax.set_xlabel("")
    #ax.get_legend().remove()
    # labels data
    for p in ax.patches:       
        x_adjust = 0.25/3
        
        value = p.get_height()
        X = p.get_x() + x_adjust
        Y = p.get_y() + p.get_height()/2
        
        XY = (X,Y)
        if value != 0:
            ax.annotate(str(round(value*100,1)) + "%",XY,fontsize = 25)

下面是我的输出:

在此处输入图像描述

所以,我对化妆品编码的问题是:

  1. 标题:我尝试使用一个主标题,plt.suptitle()但它没有按预期工作(我看不到任何输出)。还尝试了其他事情,但其他一切都引发了错误。
  2. 图例:图例看起来很难看,我不需要它们用于所有子情节。我正在尝试为所有子图只获取一个图例,这将非常棒并且可以节省空间。我尝试了类似的东西,plt.legend([CarWash[i],CarWash['ReversedPayment']], ['Blue', 'Orange'])但没有奏效。

任何意见/建议都非常受欢迎,非常感谢。谢谢你。

标签: pythonmatplotlib

解决方案


plt.suptitle在为绘图创建图形之前执行,这就是标题没有出现在最终绘图中的原因。有关如何为多个子图创建公共图例的答案,请参见此处。综合考虑,您可以尝试以下方法:

nrow = 2
ncol = len(categoricals[:-1])
fig, axes = plt.subplots(nrow,ncol, figsize = (40,20))
plt.suptitle("Distribution of target variable across the categorical variables - frequencies # and proportions %", size=40, y=1.01)

for i,ax in zip(categoricals[:-1],axes.flatten()):
    
    # plots frequencies
    df = CarWash[[i,'ReversedPayment']].value_counts().unstack().fillna(0)
    ax.bar(df.index, df[0], label='0')
    ax.bar(df.index, df[1], bottom=df[0], label='1')
    ax.tick_params(axis='both', labelsize = 25, labelrotation = 0)   
    ax.set_title(i,fontsize = 30, y=1.05)
    ax.set_xticks([0,1])
    
    # labels data
    for p in ax.patches:       
        x_adjust = 0.35
        
        value = p.get_height()
        X = p.get_x() + x_adjust
        Y = p.get_y() + p.get_height()/2
        
        XY = (X,Y)
        if value != 0:
            ax.annotate(int(value),XY,fontsize = 25)
                       
for i,ax in zip(categoricals[:-1],axes.flatten()[ncol:]):
    
    # plots proportions
    df = CarWash[[i,'ReversedPayment']].value_counts().unstack().fillna(0)
    df = (df.T/df.T.sum()).T*100
    ax.bar(df.index, df[0], label='0')
    ax.bar(df.index, df[1], bottom=df[0], label='1')
    ax.tick_params(axis='both', labelsize = 25, labelrotation = 0)   
    ax.set_title(i,fontsize = 30, y=1.05)
    ax.set_xticks([0,1])
    ax.set_ylim(0,110)

    # labels data
    for p in ax.patches:       
        x_adjust = 0.25
        
        value = p.get_height()
        X = p.get_x() + x_adjust
        Y = p.get_y() + p.get_height()/2
        
        XY = (X,Y)
        if value != 0:
            ax.annotate(str(round(value,1)) + "%",XY,fontsize = 25)
            
plt.subplots_adjust(hspace=0.4)

# plot legend
handles, labels = ax.get_legend_handles_labels()
fig.legend(handles, labels, loc=(0.95, 0.1), prop={'size': 30})
plt.show()

它给:

在此处输入图像描述


推荐阅读