添加自定义刻度和标签
我想在matplotlib中添加一个自定义的主要刻度和标签。一个常见的用法是在位置math.pi
添加一个标签,标签内容是"$\pi$"
。我的目标是保留其他的刻度不变:我希望保留之前选择的原始主要和次要刻度的格式,只是在此基础上增加这个额外的刻度和标签。我已经找到了一种方法(也在这些论坛上看到过相关帖子)来添加这个刻度:
list_loc=list(ax.xaxis.get_majorticklocs())
list_loc.append(pos)
list_loc.sort()
ax.xaxis.set_ticks(list_loc)
我遇到的问题是标签。我尝试用ax.xaxis.get_majorticklabels()
来获取标签,但这给我返回的是一个matplotlib.text.Text
的列表,我不太知道该怎么处理。我的想法是获取标签的字符串列表,添加新的标签(放在正确的位置),然后用ax.xaxis.set_ticklabels(list_label)
的方式来设置,类似于刻度的位置。
2 个回答
5
我虽然来得有点晚,但这里有我的解决方案,它可以保留原来的自动刻度位置和格式(或者你在坐标轴上设置的任何定位器/格式化器),并且简单地添加新的刻度。这个方案在你移动视图时也能正常工作,比如在图形界面中拖动或缩放。
我基本上实现了一个新的定位器和一个新的格式化器,它们会连接到原来的那些。
import matplotlib.ticker as mticker
class AdditionalTickLocator(mticker.Locator):
'''This locator chains whatever locator given to it, and then add addition custom ticks to the result'''
def __init__(self, chain: mticker.Locator, ticks) -> None:
super().__init__()
assert chain is not None
self._chain = chain
self._additional_ticks = np.asarray(list(ticks))
def _add_locs(self, locs):
locs = np.unique(np.concatenate([
np.asarray(locs),
self._additional_ticks
]))
return locs
def tick_values(self, vmin, vmax):
locs = self._chain.tick_values(vmin, vmax)
return self._add_locs(locs)
def __call__(self):
# this will call into chain's own tick_values,
# so we also add ours here
locs = self._chain.__call__()
return self._add_locs(locs)
def nonsingular(self, v0, v1):
return self._chain.nonsingular(v0, v1)
def set_params(self, **kwargs):
return self._chain.set_params(**kwargs)
def view_limits(self, vmin, vmax):
return self._chain.view_limits(vmin, vmax)
class AdditionalTickFormatter(mticker.Formatter):
'''This formatter chains whatever formatter given to it, and
then does special formatting for those passed in custom ticks'''
def __init__(self, chain: mticker.Formatter, ticks) -> None:
super().__init__()
assert chain is not None
self._chain = chain
self._additional_ticks = ticks
def __call__(self, x, pos=None):
if x in self._additional_ticks:
return self._additional_ticks[x]
res = self._chain.__call__(x, pos)
return res
def format_data_short(self, value):
if value in self._additional_ticks:
return self.__call__(value)
return self._chain.format_data_short(value)
def get_offset(self):
return self._chain.get_offset()
def _set_locator(self, locator):
self._chain._set_locator(locator)
def set_locs(self, locs):
self._chain.set_locs(locs)
这两个可以像其他定位器/格式化器一样直接使用,或者通过这个小助手方法来使用。
def axis_add_custom_ticks(axis, ticks):
locator = axis.get_major_locator()
formatter = axis.get_major_formatter()
axis.set_major_locator(AdditionalTickLocator(locator, ticks.keys()))
axis.set_major_formatter(AdditionalTickFormatter(formatter, ticks))
示例用法:
fig, ax = plt.subplots()
x = np.linspace(0,10,1000)
ax.plot(x,np.exp(-(x-np.pi)**2))
axis_add_custom_ticks(ax.xaxis, {
np.pi: '$\pi$'
})
12
这就是我通常的做法,虽然我从来没有对这个方法感到完全满意。可能还有更好的办法,不需要调用 draw()
。
fig,ax=plt.subplots()
x=linspace(0,10,1000)
x.plot(x,exp(-(x-pi)**2))
plt.draw() # this is required, or the ticklabels may not exist (yet) at the next step
labels = [w.get_text() for w in ax.get_xticklabels()]
locs=list(ax.get_xticks())
labels+=[r'$\pi$']
locs+=[pi]
ax.set_xticklabels(labels)
ax.set_xticks(locs)
ax.grid()
plt.draw()