Python 保存地物时,记号标签将被覆盖

Python 保存地物时,记号标签将被覆盖,python,matplotlib,Python,Matplotlib,我正在画“传统”相交轴: x = range(-1, 2) y = range(-1, 2) fig, ax = plt.subplots() ax.spines['left'].set_position('zero') ax.spines['bottom'].set_position('zero') ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) ax.xaxis.set_minor_locat

我正在画“传统”相交轴:

x = range(-1, 2)
y = range(-1, 2)
fig, ax = plt.subplots()
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.1))
ax.xaxis.set_major_locator(ticker.MultipleLocator(0.5))
ax.yaxis.set_minor_locator(ticker.MultipleLocator(0.1))
ax.yaxis.set_major_locator(ticker.MultipleLocator(0.5))
ax.plot(x, y)
这很好用:

我不喜欢重复的零,所以我去掉了y轴上的一个,并将x轴移到另一个:

fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.yaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)
plt.setp(next(tick for tick in ax.xaxis.get_major_ticks()
              if tick.get_loc() == 0.0).label, ha='right', text='0  ')
这几乎奏效了:

y轴零点已移除,x轴零点已正确对齐。但是,标签未按预期从
0.0
更改为
0

在调用
fig.savefig()
之前,我验证了标签确实是正确的。但是,在保存图形时,它会被重新格式化。如何正确更改标签,使其在图像中显示为
0

以下是一种解决方案:

  • 使用您的方法隐藏x或y标签
  • 以字符串形式获取剩余/现有/显示的x或y标签
  • '0.0'
    字符串替换为整数
    0
    。我使用
    [1:-1]
    ,因为在本例中
    get_text()
    的输出是由
    $
    包围的字符串,如
    $-1.0$
    $0.0$
    $1.0$
  • 最后重置x或y标签
从x轴隐藏
0.0

fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.xaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_yticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_yticklabels(new_labels)
ax.set_title('Hiding the 0.0 from x-axis')
fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.yaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_xticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_xticklabels(new_labels)
ax.set_title('Hiding the 0.0 from y-axis')

从y轴隐藏
0.0

fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.xaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_yticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_yticklabels(new_labels)
ax.set_title('Hiding the 0.0 from x-axis')
fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.yaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_xticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_xticklabels(new_labels)
ax.set_title('Hiding the 0.0 from y-axis')
这里有一个解决方案:

  • 使用您的方法隐藏x或y标签
  • 以字符串形式获取剩余/现有/显示的x或y标签
  • '0.0'
    字符串替换为整数
    0
    。我使用
    [1:-1]
    ,因为在本例中
    get_text()
    的输出是由
    $
    包围的字符串,如
    $-1.0$
    $0.0$
    $1.0$
  • 最后重置x或y标签
从x轴隐藏
0.0

fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.xaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_yticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_yticklabels(new_labels)
ax.set_title('Hiding the 0.0 from x-axis')
fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.yaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_xticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_xticklabels(new_labels)
ax.set_title('Hiding the 0.0 from y-axis')

从y轴隐藏
0.0

fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.xaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_yticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_yticklabels(new_labels)
ax.set_title('Hiding the 0.0 from x-axis')
fig.canvas.draw()  # Force the ticks to be computed now
next(tick for tick in ax.yaxis.get_major_ticks()
     if tick.get_loc() == 0.0).set_visible(False)

labels = [item.get_text()[1:-1] for item in ax.get_xticklabels()]
new_labels = [ "%d" % int(float(l)) if l == '0.0' else l for l in labels]
ax.set_xticklabels(new_labels)
ax.set_title('Hiding the 0.0 from y-axis')

我会把这个问题分开

  • 您希望在位置
    0
  • 您想移动标签
  • 在特定位置为标签创建自定义文本 一个想法是将ScalarFormatter子类化,让它返回零位置的自定义标签。这可以是一个空字符串,也可以是按您希望的方式格式化的数字零

    from matplotlib import ticker as mticker
    class CustomTicker(mticker.ScalarFormatter):
        def __init__(self, zero="0", **kwargs):
            self.zero=zero
            mticker.ScalarFormatter.__init__(self, **kwargs)
        def __call__(self, x, pos=None):
            if x != 0:
                return mticker.ScalarFormatter.__call__(self, x, pos)
            else:
                return self.zero
    
    ax.xaxis.set_major_formatter(CustomTicker(zero="0"))
    ax.yaxis.set_major_formatter(CustomTicker(zero=""))
    
    这里使用格式化程序的优点如下所述。在绘制图形之前,标签(即画布上的
    文本
    实例)没有固定的字符串。在每次后续绘制之后,该字符串可能会发生变化,这取决于轴限制或图形大小的变化。在幕后,定位器确定刻度的位置。然后,标记标签定位在标记旁边。然后,格式化程序根据位置设置标签的字符串。这是通过使用position
    x
    作为参数调用格式化程序来完成的。例如,第二个标签最初可能定位在x=-10,并显示值
    “-10”
    。更改轴的限制(例如,通过缩放)时,此同一标签可能会放置在位置x=-20处。然后,对格式化程序的调用确保其文本也被更新为显示
    “-20”
    <代码>“-10”则由第三个标签显示。想要跟踪这些变化是很麻烦的。因此,操纵格式化程序本身,就不必关心那些内部构件

    移动单个标签 虽然标签的许多属性是以集中的方式设置的,但它们的实际转换不是这样的。因此,可以通过变换来转换单个标签。在这里,我们可以选择在像素空间中对其进行平移(即,在执行主变换之后)。由于单个标签在更改限制时(即缩放或平移时)可能会更改其内容,因此我们可能会创建一个回调来更改零位置处一个标签的变换,而与实际限制无关。 在下文中,我们将
    “0”
    转换为
    -10
    像素

    import matplotlib.transforms as mtrans
    
    basetrans = ax.get_xticklabels()[0].get_transform()
    def movelabel(evt=None):
        trans = basetrans + mtrans.Affine2D().translate(-10,0)
        for tick in ax.xaxis.get_major_ticks():
            if tick.get_loc() == 0.0:
                tick.label.set_transform(trans)
            else:
                tick.label.set_transform(basetrans)
    
    fig.canvas.draw()
    movelabel()
    ax.callbacks.connect('xlim_changed', movelabel)
    ax.callbacks.connect('ylim_changed', movelabel)
    
    完整代码:

    我会把这个问题分开

  • 您希望在位置
    0
  • 您想移动标签
  • 在特定位置为标签创建自定义文本 一个想法是将ScalarFormatter子类化,让它返回零位置的自定义标签。这可以是一个空字符串,也可以是按您希望的方式格式化的数字零

    from matplotlib import ticker as mticker
    class CustomTicker(mticker.ScalarFormatter):
        def __init__(self, zero="0", **kwargs):
            self.zero=zero
            mticker.ScalarFormatter.__init__(self, **kwargs)
        def __call__(self, x, pos=None):
            if x != 0:
                return mticker.ScalarFormatter.__call__(self, x, pos)
            else:
                return self.zero
    
    ax.xaxis.set_major_formatter(CustomTicker(zero="0"))
    ax.yaxis.set_major_formatter(CustomTicker(zero=""))
    
    这里使用格式化程序的优点如下所述。在绘制图形之前,标签(即画布上的
    文本
    实例)没有固定的字符串。在每次后续绘制之后,该字符串可能会发生变化,这取决于轴限制或图形大小的变化。在幕后,定位器确定刻度的位置。然后,标记标签定位在标记旁边。然后,格式化程序根据位置设置标签的字符串。这是通过使用position
    x
    作为参数调用格式化程序来完成的。例如,第二个标签最初可能定位在x=-10,并显示值
    “-10”
    。更改轴的限制(例如,通过缩放)时,此同一标签可能会放置在位置x=-20处。然后,对格式化程序的调用确保其文本也被更新为显示
    “-20”
    <代码>“-10”则由第三个标签显示。想要跟踪这些变化是很麻烦的。因此,操纵格式化程序本身,就不必关心那些内部构件

    移动单个标签 虽然标签的许多属性是以集中的方式设置的,但它们的实际转换不是这样的。因此,可以通过变换来转换单个标签。在这里,我们可以选择在像素空间中对其进行平移(即,在执行主变换之后)。B