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

Matplotlib双Y轴分组标签导致热力图截断问题排查

问题描述

尝试为热力图的Y轴标签添加分组,通过第二个Y轴实现该功能,但添加后热力图上下部分被截断,图表边框也发生异常;移除第二个Y轴相关代码后,热力图显示正常。怀疑par2 = ax.twinx()存在问题,但使用ax.twiny()效果更差,询问错误原因及解决方法。

问题分析

核心问题出在两个方面:

  • twinx()创建的双Y轴会与原轴共享X轴,你将par2的左侧spine移到了图表外部(("axes", -0.3)),但fig.tight_layout()在计算布局时未考虑这个额外的左侧空间,导致热力图被挤压截断。
  • 未正确处理imshow默认的origin='upper'设置:原Y轴的范围是(6.5, -0.5)(从上到下对应索引0到6),但你设置的par2刻度位置[-0.5, 3.5, 6.5]与这个范围方向相反,导致分组标签位置错误。
修复后的代码
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

vegetables = ["cucumber", "tomato", "lettuce", "asparagus",
              "potato", "wheat", "barley"]
farmers = ["Farmer Joe", "Upland Bros.", "Smith Gardening",
           "Agrifun", "Organiculture", "BioGoods Ltd.", "Cornylee Corp."]

harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])

# 调整子图左边距,为分组标签留出空间
fig, ax = plt.subplots(figsize=(8,6))
fig.subplots_adjust(left=0.25)

im = ax.imshow(harvest)

# 旋转X轴标签
plt.setp(ax.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor")

# 添加单元格注释
for i in range(len(vegetables)):
    for j in range(len(farmers)):
        text = ax.text(j, i, harvest[i, j], ha="center", va="center", color="w")

ax.set_xticks(np.arange(len(farmers)), labels=farmers)
ax.set_yticks(np.arange(len(vegetables)), labels=vegetables)

# 添加第二个Y轴用于分组
par2 = ax.twinx()
# 匹配原轴的Y范围(因origin='upper',范围是(6.5, -0.5))
par2.set_ylim(ax.get_ylim())

# 移动左侧spine到图表外,调整位置参数适配留出的左边距
par2.spines["left"].set_position(("axes", -0.2))
# 隐藏par2不需要的spine,避免干扰原图表边框
par2.spines["right"].set_visible(False)
par2.spines["top"].set_visible(False)
par2.spines["bottom"].set_visible(False)

# 设置刻度样式
par2.tick_params('both', length=0, width=0, which='minor')
par2.tick_params('both', direction='in', which='major')
par2.yaxis.tick_left()
par2.yaxis.set_label_position("left")
par2.spines["left"].set_visible(True)

# 设置分组相关刻度
par2.yaxis.set_major_formatter(ticker.NullFormatter())
# 匹配原轴的方向,设置正确的刻度位置
par2.set_yticks([6.5, 3.5, -0.5])
# 分组标签的位置对应分组的中间点
par2.yaxis.set_minor_locator(ticker.FixedLocator([4.5, 1.5]))
par2.yaxis.set_minor_formatter(ticker.FixedFormatter(['tasty', 'not tasty']))

ax.set_title("Harvest of local farmers (in tons/year)")
plt.show()
关键修复点
  • 通过fig.subplots_adjust(left=0.25)手动调整左侧边距,为分组标签预留空间,避免tight_layout挤压图表。
  • 隐藏par2的右侧、顶部、底部spine,防止破坏原图表的边框样式。
  • 根据imshow默认的origin='upper',调整par2的刻度位置,确保分组标签显示在正确的分组中间位置。
  • 调整par2的spine偏移量,适配预留的左边距,避免标签被截断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:05:18