Я бы разделил проблему.
- Вы хотите иметь собственный текст для метки в позиции
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
на холсте) не установлена фиксированная строка, пока не будет нарисована фигура.И эта строка может затем меняться после каждого последующего рисования, в зависимости от границ оси или изменения размера фигуры.За кулисами локатор определяет местоположение галочек.Ticklabels затем располагаются рядом с галочками.Форматировщик затем устанавливает строку метки, в зависимости от позиции.Это делается путем вызова средства форматирования с позицией 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()
