python - 保存图形时,刻度标签被覆盖
问题描述
我正在画“传统”相交轴:
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 轴 1 正确对齐。然而,标签并没有像预期的那样从0.0
更改为 。0
我在调用 之前验证fig.savefig()
了标签确实是正确的。但是,保存图形时会重新格式化。如何正确更改标签以使其0
在图像中读取?
解决方案
我会拆分问题。
- 您希望在位置标签有一个自定义文本
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=""))
在这里使用格式化程序的好处可以理解如下。在绘制图形之前,刻度标签(即Text
画布上的实例)没有设置固定字符串。然后,此字符串可能会在每次后续绘制之后更改,具体取决于轴限制或图形大小的更改。在幕后,定位器确定刻度的位置。然后将刻度标签定位在刻度旁边。然后格式化程序根据位置设置标签的字符串。这是通过使用位置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)
完整代码:
import matplotlib.pyplot as plt
from matplotlib import ticker as mticker
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(mticker.MultipleLocator(0.1))
ax.xaxis.set_major_locator(mticker.MultipleLocator(0.5))
ax.yaxis.set_minor_locator(mticker.MultipleLocator(0.1))
ax.yaxis.set_major_locator(mticker.MultipleLocator(0.5))
ax.plot(x, y)
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=""))
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)
plt.show()
推荐阅读
- git - Git 作者的名字后面有一个星号
- python-3.6 - 可以在具有 IBM PPC 架构的 RHEL7 上安装 python36 吗?
- angular - Angular 6 - 使用 Angular 材质的动态页面
- c++ - 关于二进制数字的 int 数组
- eclipse - eclipse中的mercurial插件 - 无法满足依赖错误
- ffmpeg - ffmpeg .264 视频转换为 jpg
- julia - 朱莉娅 | 数组元素作为另一个数组的参数
- android - Android 模拟器未激活
- swift - 如何在 linux 上快速线程睡眠
- c++ - 带有条件 constexpr 注释的 C++ 代码与 ODR 和链接器