You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib子图行列标签添加及每行右侧标注RMSE的实现方法

标量场廓线图绘制优化方案

核心问题解决方案

问题1:子图行列统一添加标签,避免重复标注拥挤

使用matplotlib子图的轴共享特性即可实现,同一列共享x轴、同一行共享y轴,仅在最底部子图显示x轴刻度标签、最左侧子图显示y轴刻度标签,配合Figure级别的全局轴标签即可完成统一标注:

  • 创建子图时指定sharex='col'、sharey='row'参数
  • 保留原有的fig.supxlabel、fig.supylabel设置全局轴名称

问题2:每行右侧标注对应总RMSE

给每行最后一个子图添加隐藏刻度的右侧Y轴,用该轴的ylabel来展示RMSE数值,位置会自动对齐行居中:

  • 遍历每个标量(每一行)时记录行索引
  • 该行所有子图绘制完成后,获取行末子图调用twinx()创建右侧轴
  • 隐藏右侧轴的刻度,仅保留RMSE文本标签

优化后完整可运行代码

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

# 补充缺失的归一化函数(开启norm参数时需要)
def normalize_list(arr):
    if arr.max() == arr.min():
        return arr
    return (arr - arr.min()) / (arr.max() - arr.min())

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 ):
    n_rows = len(true_var.keys())
    n_cols = len(x_position)
    # 创建共享轴的子图,避免重复标注
    fig, axes = plt.subplots(n_rows, n_cols, figsize=(13,10), sharex='col', sharey='row')
    st = plt.suptitle("标量场廓线对比", fontsize="x-large", y=0.98)
    
    scalar_list = list(true_var.keys())
    for row_idx, key in enumerate(scalar_list):
        rmse_list = []
        # 计算当前标量的全局x范围,统一该行所有子图x轴
        all_profiles = np.concatenate([true_var[key][..., pos] for pos in x_position] + 
                                     [pred_var[key][..., pos] for pos in x_position])
        x_min, x_max = all_profiles.min() * 1.05, all_profiles.max() * 1.05
      
        for col_idx, profile_pos in enumerate(x_position):
            ax = axes[row_idx, col_idx]
            # 仅第一行加列标题(x位置)
            if row_idx == 0:
                ax.set_title(f"X_pos: {profile_pos}")
            # 仅第一列加行标题(标量名+Y轴标签)
            if col_idx == 0:
                ax.set_ylabel(f"标量{key}\ny Distance (cm)")
            
            true_field_star = true_var[key]
            pred_field_star = pred_var[key]
            true_profile = true_field_star[...,profile_pos]
            pred_profile = pred_field_star[...,profile_pos] 

            if norm:
              true_profile = normalize_list(true_profile)
              pred_profile = normalize_list(pred_profile)
    
            rms = mean_squared_error(true_profile, pred_profile, squared=False)
            profile_y = range(len(true_profile))
            # 线条样式区分真实值和预测值
            ax.plot(true_profile, profile_y, label='真实值', color='#1f77b4', linewidth=1.5)
            ax.plot(pred_profile, profile_y, label='预测值', color='#ff7f0e', linestyle='--', linewidth=1.5)
            # 子图角落标注当前位置RMSE
            ax.text(0.95, 0.05, f"RMSE: {rms:.2f}", transform=ax.transAxes, 
                    ha='right', va='bottom', bbox=dict(facecolor='white', alpha=0.7))
            ax.set_xlim(x_min, x_max)
            ax.grid(alpha=0.3, linestyle=':')
            rmse_list.append(rms) 
        
        # 每行末尾添加总RMSE标注
        RMSE = sum(rmse_list)
        print(f"RMSE {key}: {RMSE}")
        last_ax = axes[row_idx, -1]
        rmse_ax = last_ax.twinx()
        rmse_ax.set_yticks([])
        rmse_ax.set_ylabel(f"总RMSE\n{RMSE:.2f}", labelpad=15, fontweight='bold', color='#d62728')
        
    # 全局设置
    lines, labels = axes[0,0].get_legend_handles_labels()    
    fig.legend(lines, labels, loc = "lower right", bbox_to_anchor=(0.98, 0.02)) 
    fig.supxlabel('u Velocity (m/s)', x=0.5)
    # 调整布局,给右侧RMSE和顶部标题留空间
    fig.tight_layout(rect=[0, 0, 0.92, 0.96])
  
    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轴范围:避免不同位置的廓线因为轴范围不同造成视觉对比误差
  • 线条样式+颜色双区分:真实值用实线、预测值用虚线,即使黑白打印也能清晰区分
  • 子图添加单位置RMSE标注:可同时查看全局总误差和每个x位置的局部误差
  • 半透明背景的文本标注:避免标注遮挡廓线数据
  • 增加浅灰色网格:方便读取廓线对应的数值

内容的提问来源于stack exchange,提问作者Zizi96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 07:48:01