【问题标题】:How to fix the legend and the main title for all the subplots in matplotlib?如何修复 matplotlib 中所有子图的图例和主标题?
【发布时间】:2021-09-03 15:10:11
【问题描述】:

我是 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. Legend:Legend 看起来很难看,我不需要它们用于所有子情节。我正在尝试为所有子图只获取一个图例,这将非常棒并且可以节省空间。我尝试了类似 plt.legend([CarWash[i],CarWash['ReversedPayment']], ['Blue', 'Orange']) 的方法,但没有成功。

欢迎和非常感谢任何 cmets / 建议。谢谢。

【问题讨论】:

  • try figure.suptitle("目标变量在分类变量中的分布-频率#和比例%",fontsize=20)

标签: python matplotlib


【解决方案1】:

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

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()

它给出:

【讨论】:

    【解决方案2】:

    也许您可以将标题移动到循环中并在迭代后添加图例,如下所示。

    nrow = 1
    ncol = len(categoricals[:-1])
    figure, axes = plt.subplots(nrow,ncol, figsize = (20,5))
    
    
    for i,ax in zip(categoricals[:-1],axes.flatten()):    
        # plots frequencies
        plt.suptitle("Distribution of target variable across the categorical variables - frequencies # and proportions %")
    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 = 15, labelrotation = 0)   
        ax.set_title(i,fontsize = 15)
        ax.set_xlabel("")
        legend = ax.legend()
        #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
            legend.remove()
        
            XY = (X,Y)
            if value != 0:
            ax.annotate(int(value),XY,fontsize = 15)    
    
    ax.legend(loc=2, bbox_to_anchor=(-4.2,1.1),fontsize=10) 
    

    输出图如下所示,仍然需要进行一些调整以包括第二行子图和定位/尺寸。

    对于涉及许多标签、图例、附录的科学情节,您可以使用另一个 Python 驱动的程序,称为 Veusz。这也很容易使用。 Veusz website

    【讨论】:

      猜你喜欢
      • 2011-11-23
      • 2015-07-08
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2021-11-01
      • 2014-11-06
      • 2021-01-17
      • 2019-05-28
      相关资源
      最近更新 更多