使用Matplotlib子图时Y轴范围与字体不一致的解决方法
解决子图Y轴范围波动与字体不一致问题
问题根源分析
1. Y轴范围持续变化
原代码存在两个核心问题导致Y轴范围不稳定:
- 画布创建位置错误:在遍历每个通道的循环内创建
fig,导致每个通道单独生成画布,而非在同一个画布中生成子图,根本没实现真正的子图布局。 - Y轴范围未针对性控制:全局传入的
ylim对所有子图生效,未根据不同电气参数的特性设置对应范围,也未提前统计数据的极值来固定范围。
2. 字体不一致
代码中分散设置了多种字体大小(如title_font、Y_font、X_font、刻度字体4、图例3.5),且未统一字体类型,同时部分文本元素的字体设置可能遗漏。
解决方案与修改后代码
关键调整点
- 将画布
fig的创建移到通道分块(chunk)的循环内,确保同一个分块的所有通道在同一个画布生成子图。 - 提前读取当前分块所有通道的数据,统计每个通道的Y轴极值,用于固定范围;也支持传入针对单个通道的Y轴范围配置。
- 全局统一字体设置,通过
plt.rcParams预设字体大小和类型,避免分散设置导致的不一致。
修改后的代码:
import glob import os import sys import pandas as pd import matplotlib.pyplot as plt # 全局统一字体设置 plt.rcParams['font.size'] = 8 plt.rcParams['font.family'] = 'Arial' # 可替换为你需要的字体 def Naming_Ylabels(chan_name): # 保留你原有的Y轴标签命名逻辑,示例如下 if "FREQ" in chan_name: return "Frequency [Hz]" elif "VOLT" in chan_name: return "Voltage [kV]" else: return chan_name def plot_subplots(Monitor_Channels, subTitle, **kwarg): outfiles = glob.glob(os.path.join(os.getcwd(), "PSSE_Data", "*.csv")) if not Monitor_Channels: print("No channels available to plot !") sys.exit() for outfile in outfiles: # 按每6个通道分块处理 for k, j in enumerate(range(0, len(Monitor_Channels), 6)): chunk = Monitor_Channels[j:j+6] nrows = len(chunk) ncols_sub = 1 if nrows % 2 != 0 else 2 # 先读取当前分块所有通道的数据,统计Y轴范围 chunk_data = {} for chans in chunk: df = pd.read_csv(outfile, usecols=['Time', chans], index_col=False, header=0) t = df['Time'].values chan_data = df[chans].values if "FREQ" in chans: chan_data = 50 * (1 + chan_data) chunk_data[chans] = (t, chan_data) # 创建单个画布,用于放置当前分块的所有子图 fig_name = f"{os.path.basename(outfile[:-4])}{subTitle}" fig = plt.figure(fig_name, linewidth=0.5, figsize=(8, 12)) fig.suptitle(os.path.basename(outfile[:-4]), fontsize=10, y=0.98) for n, chans in enumerate(chunk): t, chan_data = chunk_data[chans] # 创建子图 ax = plt.subplot(nrows, ncols_sub, n + 1) ax.grid(which='major', color='#DDDDDD', linewidth=0.7) ax.grid(which='minor', color='#EEEEEE', linestyle=':', linewidth=0.4) ax.minorticks_on() ax.plot(t, chan_data, linestyle='-', linewidth=1, color="blue", label=chans) # 设置Y轴标签和范围 ax.set_ylabel(Naming_Ylabels(chans)) # 优先使用传入的对应通道的ylim,否则用数据的极值(留5%余量) if 'ylim_dict' in kwarg and chans in kwarg['ylim_dict']: y_min, y_max = kwarg['ylim_dict'][chans] else: y_min, y_max = chan_data.min() * 0.95, chan_data.max() * 1.05 ax.set_ylim([y_min, y_max]) # 设置X轴范围和标签 ax.set_xlim([t[0], t[-1]]) ax.set_xlabel('Time [s]') # 图例设置(统一字体大小) ax.legend(loc='best', prop={'size': 7}, ncol=2) plt.tight_layout(h_pad=0.5, top=0.95) save_name = f"{k}_{os.path.basename(outfile[:-4])}_{subTitle}.pdf" plt.savefig(save_name, bbox_inches='tight') plt.close() # 使用示例(按需调整) # Monitor_Channels = ['FREQ_1', 'VOLT_2', 'CURR_3'] # ylim_config = {'FREQ_1': (49.5, 50.5), 'VOLT_2': (0.9, 1.1)} # plot_subplots(Monitor_Channels, 'TestPlot', ylim_dict=ylim_config)
额外说明
- 如果需要针对特定参数类统一Y轴范围(比如所有频率子图用相同范围),可以在统计数据时按参数类型分组计算极值。
- 全局字体设置可以根据需求调整
plt.rcParams的参数,比如font.size、font.family等,确保所有文本元素风格统一。
内容的提问来源于stack exchange,提问作者Md Shamiur Rahman Shaummo
相关产品推荐
相关产品推荐

