如何为子图的行和列添加标签?

How do I add labels to subplot rows and columns?

我创建了以下函数,它从标量场创建标量剖面图。

import numpy as np 
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error



dummy_data_A = {'A': np.random.uniform(low=-3.5, high=3.5, size=(98,501)), 
                'B': np.random.uniform(low=-3.5, high=3.5, size=(98,501)), 'C': np.random.uniform(low=-3.5, high=3.5, size=(98,501))}
dummy_data_B = {'A': np.random.uniform(low=-3.5, high=3.5, size=(98,501)), 
                'B': np.random.uniform(low=-3.5, high=3.5, size=(98,501)), 'C': np.random.uniform(low=-3.5, high=3.5, size=(98,501))}


def plot_scalar_profiles(true_var, pred_var,  
                         coordinates = ['x','y'], 
                         x_position = None, 
                         bounds_var = None, 
                         norm = False ):
    
    fig = plt.figure(figsize=(12,10))
    st = plt.suptitle("Scalar fields", fontsize="x-large")
 
    nr_plots = len(list(true_var.keys())) # not plotting x or y
    plot_index = 1
   
    for key in true_var.keys():
        rmse_list = []
      
        for profile_pos in x_position:  

            
            true_field_star = true_var[key]
            pred_field_star = pred_var[key]
            
                
            axes = plt.subplot(nr_plots, len(x_position), plot_index)
            axes.set_title(f"scalar: {key},  X_pos: {profile_pos}")   # ,RMSE: {rms:.2f}
            
            
            true_profile = true_field_star[...,profile_pos]   # for i in range(probe positions)
            pred_profile = pred_field_star[...,profile_pos] 

            if norm:
              #true_profile = true_field_star[...,profile_pos]   # for i in range(probe positions)
              #pred_profile = pred_field_star[...,profile_pos] 
              true_profile = normalize_list(true_field_star[...,profile_pos])
              pred_profile = normalize_list(pred_field_star[...,profile_pos])
    
            rms = mean_squared_error(true_profile, pred_profile, squared=False)
            

            true_profile_y = range(len(true_profile))
            axes.plot(true_profile, true_profile_y, label='True')
            
            #
            pred_profile_y = range(len(pred_profile))
            axes.plot(pred_profile, pred_profile_y, label='Pred')
            
            rmse_list.append(rms) 
            plot_index += 1
        
        RMSE = sum(rmse_list)
        print(f"RMSE {key}: {RMSE}")
        
    lines, labels = fig.axes[-1].get_legend_handles_labels()    
    fig.legend(lines, labels, loc = "lower right") 
    fig.supxlabel('u Velocity (m/s)')
    fig.supylabel('y Distance (cm)')
    fig.tight_layout()
  
    #plt.savefig(save_name + '.png', facecolor='white', transparent=False)
    plt.show()
    plt.close('all')
    
plot_scalar_profiles(dummy_data_A, dummy_data_B, 
                     x_position = [1, 100, 200, 400], 
                     bounds_var=None, 
                     norm=False) 

它还计算沿 x_position 为标量场 'A''B''C'.

提取的剖面的总均方根误差
Console output:
RMSE A: 11.815624240063709
RMSE B: 11.623509385371737
RMSE C: 11.435156749416366

有两件事我有疑问:

  1. 如何标记每行和每列?标记每个子图看起来很混乱。

  2. 如何在每行右侧注释 RMSE 输出?

这是我对 2 点的粗略描述。

也欢迎任何其他改进建议。我仍在尝试找出表示此数据的 cleanest/best 方法。

假设

我的回答基于你总是有 12 个地块的假设,所以我将注意力集中在一些位置固定的地块上。

回答

为了标记每一行,您可以使用 fig.axes[n].set_ylabel 设置左侧绘图的 y 标签,您可以选择添加其他参数来自定义标签:

fig.axes[0].set_ylabel('A', rotation = 0, weight = 'bold', fontsize = 12)
fig.axes[4].set_ylabel('B', rotation = 0, weight = 'bold', fontsize = 12)
fig.axes[8].set_ylabel('C', rotation = 0, weight = 'bold', fontsize = 12)

为了报告每一行的 RMSE,您需要将这些值保存在一个列表中,然后您可以利用与上面相同的概念:在右侧设置图表的 y 标签,然后将 y 标签向右移动:

    RMSE = sum(rmse_list)
    RMSE_values.append(RMSE)
    print(f"RMSE {key}: {RMSE}")

...

fig.axes[3].set_ylabel(f'RMSE = {RMSE_values[0]:.2f}', rotation = 0, weight = 'bold', fontsize = 12, labelpad = 50)
fig.axes[7].set_ylabel(f'RMSE = {RMSE_values[1]:.2f}', rotation = 0, weight = 'bold', fontsize = 12, labelpad = 50)
fig.axes[11].set_ylabel(f'RMSE = {RMSE_values[2]:.2f}', rotation = 0, weight = 'bold', fontsize = 12, labelpad = 50)
fig.axes[3].yaxis.set_label_position('right')
fig.axes[7].yaxis.set_label_position('right')
fig.axes[11].yaxis.set_label_position('right')

完整代码

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error

dummy_data_A = {'A': np.random.uniform(low = -3.5, high = 3.5, size = (98, 501)),
                'B': np.random.uniform(low = -3.5, high = 3.5, size = (98, 501)),
                'C': np.random.uniform(low = -3.5, high = 3.5, size = (98, 501))}
dummy_data_B = {'A': np.random.uniform(low = -3.5, high = 3.5, size = (98, 501)),
                'B': np.random.uniform(low = -3.5, high = 3.5, size = (98, 501)),
                'C': np.random.uniform(low = -3.5, high = 3.5, size = (98, 501))}


def plot_scalar_profiles(true_var, pred_var,
                         coordinates = ['x', 'y'],
                         x_position = None,
                         bounds_var = None,
                         norm = False):
    fig = plt.figure(figsize = (12, 10))
    st = plt.suptitle("Scalar fields", fontsize = "x-large")

    nr_plots = len(list(true_var.keys()))  # not plotting x or y
    plot_index = 1
    RMSE_values = []

    for key in true_var.keys():
        rmse_list = []

        for profile_pos in x_position:

            true_field_star = true_var[key]
            pred_field_star = pred_var[key]

            axes = plt.subplot(nr_plots, len(x_position), plot_index)
            axes.set_title(f"scalar: {key},  X_pos: {profile_pos}")  # ,RMSE: {rms:.2f}

            true_profile = true_field_star[..., profile_pos]  # for i in range(probe positions)
            pred_profile = pred_field_star[..., profile_pos]

            if norm:
                # true_profile = true_field_star[...,profile_pos]   # for i in range(probe positions)
                # pred_profile = pred_field_star[...,profile_pos]
                true_profile = normalize_list(true_field_star[..., profile_pos])
                pred_profile = normalize_list(pred_field_star[..., profile_pos])

            rms = mean_squared_error(true_profile, pred_profile, squared = False)

            true_profile_y = range(len(true_profile))
            axes.plot(true_profile, true_profile_y, label = 'True')

            #
            pred_profile_y = range(len(pred_profile))
            axes.plot(pred_profile, pred_profile_y, label = 'Pred')

            rmse_list.append(rms)
            plot_index += 1

        RMSE = sum(rmse_list)
        RMSE_values.append(RMSE)
        print(f"RMSE {key}: {RMSE}")

    lines, labels = fig.axes[-1].get_legend_handles_labels()
    fig.legend(lines, labels, loc = "lower right")
    fig.supxlabel('u Velocity (m/s)')
    fig.supylabel('y Distance (cm)')

    fig.axes[0].set_ylabel('A', rotation = 0, weight = 'bold', fontsize = 12)
    fig.axes[4].set_ylabel('B', rotation = 0, weight = 'bold', fontsize = 12)
    fig.axes[8].set_ylabel('C', rotation = 0, weight = 'bold', fontsize = 12)

    fig.axes[3].set_ylabel(f'RMSE = {RMSE_values[0]:.2f}', rotation = 0, weight = 'bold', fontsize = 12, labelpad = 50)
    fig.axes[7].set_ylabel(f'RMSE = {RMSE_values[1]:.2f}', rotation = 0, weight = 'bold', fontsize = 12, labelpad = 50)
    fig.axes[11].set_ylabel(f'RMSE = {RMSE_values[2]:.2f}', rotation = 0, weight = 'bold', fontsize = 12, labelpad = 50)
    fig.axes[3].yaxis.set_label_position('right')
    fig.axes[7].yaxis.set_label_position('right')
    fig.axes[11].yaxis.set_label_position('right')

    fig.tight_layout()

    # plt.savefig(save_name + '.png', facecolor='white', transparent=False)
    plt.show()
    plt.close('all')


plot_scalar_profiles(dummy_data_A, dummy_data_B,
                     x_position = [1, 100, 200, 400],
                     bounds_var = None,
                     norm = False)

情节