【问题标题】:Matplotlib: Center tick-labels between subplotsMatplotlib:子图之间的中心刻度标签
【发布时间】:2015-01-28 11:00:49
【问题描述】:

默认情况下,刻度标签在它们所属的子图轴上对齐。 是否可以对齐标签,使它们在两个子图之间居中?

import numpy as np
import matplotlib.pyplot as plt

data = [7, 2, 3, 0]
diff = [d - data[0] for d in data]
y = np.arange(len(data))

ax1 = plt.subplot(1, 2, 1)
ax1.barh(y, diff)
ax1.set_yticks(y + 0.4)
ax1.yaxis.set_major_formatter(matplotlib.ticker.NullFormatter())

ax2 = plt.subplot(1, 2, 2)
ax2.barh(y, data)
ax2.set_yticks(y + 0.4)
ax2.set_yticklabels(['reference', 'something', 'something else', 'nothing', ])

plt.tight_layout()
plt.show()

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    这是一种可行但不是很方便的方法。您可以在设置xticklabels 时提供position 关键字。这允许您在轴坐标中使用负偏移。如果您手动设置轴的位置和它们之间的间距,您可以计算出这个负偏移量需要多少才能使标签准确地位于两个轴之间的中心。

    鉴于您的示例数据:

    fig = plt.figure(figsize=(10, 2), facecolor='w')
    fig.subplots_adjust(wspace=0.2)
    
    ax1 = fig.add_axes([0.0, 0, 0.4, 1])
    ax2 = fig.add_axes([0.6, 0, 0.4, 1])
    
    ax1.barh(y, diff, align='center')
    ax1.set_yticks(y)
    ax1.yaxis.set_major_formatter(matplotlib.ticker.NullFormatter())
    
    ax2.barh(y, data, align='center')
    ax2.set_yticks(y)
    ax2.set_yticklabels(['reference', 'something', 'something else', 'nothing', ], 
                        ha='center', position=(-0.25, 0))
    

    坐标轴在图形坐标中的宽度均为 0.4,它们之间的间距为 0.2。这意味着标签必须在图形坐标中为 0.5。由于第二个轴从 0.6 开始,因此图形坐标中的偏移量需要 -0.1。不幸的是,位置应该在轴坐标中给出。坐标区的宽度为 0.4,因此图形坐标中四分之一的坐标区宽度为 0.1。这意味着指定负四分之一的偏移量 -0.25 会将标签放置在两个轴之间。我希望这是有道理的.....

    请注意,我将yticklabelsha='center' 居中。并且还使您的条居中,因此您在设置ticks 时不必再指定偏移量。

    编辑:

    您可以通过读取两个轴的位置来自动完成。

    def center_ylabels(ax1, ax2):
    
        pos2 = ax2.get_position()
        right = pos2.bounds[0]    
    
        pos1 = ax1.get_position()
        left = pos1.bounds[0] + pos1.bounds[2]
    
        offset = ((right - left) / pos2.bounds[2]) * -0.5
    
        for yt in ax2.get_yticklabels():        
            yt.set_position((offset, yt.get_position()[1]))
            yt.set_ha('center')
    
            plt.setp(ax2.yaxis.get_major_ticks(), pad=0)
    
    fig, (ax1, ax2) = plt.subplots(1,2, figsize=(10,2))
    fig.subplots_adjust(wspace=0.5)
    
    ax1.barh(y, diff, align='center')
    ax1.set_yticks(y)
    ax1.yaxis.set_major_formatter(matplotlib.ticker.NullFormatter())
    
    ax2.barh(y, data, align='center')
    ax2.set_yticks(y)
    ax2.set_yticklabels(['reference', 'something', 'something else', 'nothing'])
    
    center_ylabels(ax1, ax2)
    

    【讨论】:

    • 好建议,谢谢。请原谅我(还)不接受您的回答,但我仍然希望有人能提出自动解决方案...
    • 您也可以使用此技术自动执行此操作。我已经编辑了我的答案。
    • 还是要手动调整子图间距不是吗?
    • 不,不是为了使 ylabels 居中。您也可以将它与您的示例一起使用,只要在调用 tight_layout 之后放置函数 center_ylabels(ax1, ax2),因为该函数会与轴位置混淆。
    • 对,行得通。知道为什么标签不完全居中,而是稍微向左移动吗?