matplotlib 2x2共享轴子图末图无数据破坏对数刻度问题求解
问题原因
你开启了全局y轴共享,但仅给有数据的子图设置了对数刻度,空数据子图既没有设置对数刻度,也没有主动限制y轴范围。matplotlib会自动同步所有共享轴的刻度规则和范围,最后绘制的空子图默认使用线性刻度、y轴范围为[0,1],和前面子图的对数刻度范围冲突,最终导致全局刻度异常。
修复方案1:提前统一配置刻度与范围(推荐)
提前给所有子图统一设置对数刻度,再根据有效数据的取值范围固定全局y轴上下限即可,既保留所有子图结构,也不会破坏刻度规则。
修复后代码如下:
import matplotlib.pyplot as plt n_plots_per_fig = 4 nrows = 2 ncols = 2 fig, axs = plt.subplots(nrows, ncols, sharex="all", sharey="all", figsize=(8, 6)) axs = axs.ravel() # 提前统一设置所有子图的y轴为对数刻度 for ax in axs: ax.set_yscale("log") # 统计所有有效数据的y轴范围,也可根据业务场景直接预设合理范围 y_min, y_max = float("inf"), float("-inf") valid_data_list = [] # 先绘制所有有数据的子图,统计取值范围 for i, ax in enumerate(axs): x = [1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] bins = 3 ax.set_title(str(i), fontsize="medium") # 跳过空数据子图,后续统一处理 if i == n_plots_per_fig - 1: valid_data_list.append(False) continue valid_data_list.append(True) if x: n, _, _ = ax.hist(x, bins=bins) # 过滤0值避免对数刻度报错,更新范围 valid_n = n[n > 0] if len(valid_n) > 0: y_min = min(y_min, valid_n.min()) y_max = max(y_max, valid_n.max()) # 统一设置全局y轴范围,留适当边距 for ax in axs: ax.set_ylim(y_min * 0.5, y_max * 2) # 最后处理空数据子图,添加NA文本 for i, ax in enumerate(axs): if not valid_data_list[i]: ax.text(0.5, 0.5, 'NA', ha='center', va='center', transform=ax.transAxes) plt.show()
修复方案2:解除空数据子图的共享关系
如果需要不同子图使用不同刻度规则,可以在绘制空数据子图前就解除其y轴共享,避免影响全局刻度,只需在空数据处理分支添加两行代码即可:
# 仅移除当前空子图的y轴共享关系 ax.get_shared_y_axes().remove(ax) # 隐藏空子图的刻度,避免显示异常 ax.set_yticks([])
内容的提问来源于stack exchange,提问作者Egelbets
相关产品推荐
相关产品推荐

