我可能很想使用plt.annotate 来绘制带标签的箭头:
import numpy as np
import matplotlib.pyplot as plt
time = np.linspace(1500, 2000)
yvals = np.exp(time * 0.01)
myLabels = {1500:'Awful times', 1800:'Somewhat better times',
1930:'Bad again', 1990:'We are alright'}
fig, ax = plt.subplots(1, 1)
ax.plot(time, yvals)
for x, label in myLabels.iteritems():
ax.annotate(label, xy=(x, np.exp(x * 0.01)), xytext=(-40, 40),
xycoords='data', textcoords='offset points',
ha='center', va='bottom', fontsize='large',
arrowprops=dict(arrowstyle='->', lw=2))
ax.set_xlim(1300, 2100)
ax.set_ylim(0, yvals.max() * 1.2)
从 cmets 看来,您希望在时间轴上表示值范围而不是单个时间点,并且您希望在同一组轴上绘制多个系列(因此您不希望注释的任何方面随时间序列的 y 值而变化)。
确实有很多方法可以做到这一点,但我仍然不太确定你在寻找什么。一个相当简单的选择是使用 plt.axvspan 绘制彩色阴影区域(类似于 chepyle 的答案,除了不改变高度)并使用图例显示标签:
edges, labels = zip(*sorted(myLabels.iteritems()))
edges = edges + (2000,)
colors = ['r', 'b', 'g', 'c']
for ii, ll in enumerate(labels):
ax.axvspan(edges[ii], edges[ii + 1], facecolor=colors[ii],
label=labels[ii], alpha=0.3)
ax.legend(loc='upper left')
使用图例的好处是您不必担心在最后一个范围内塞入文本标签,因为范围很窄。
您也可以使用垂直线并挤压上面的标签(可选用双端箭头来表示范围):
from matplotlib.transforms import blended_transform_factory
# x-position specified in data coordinates, y-position specified in [0, 1]
# relative axis coordinates
tform = blended_transform_factory(ax.transData, ax.transAxes)
edges, labels = zip(*sorted(myLabels.iteritems()))
edges = np.r_[edges, 2000]
centers = (edges[:-1] + edges[1:]) / 2.
# mark edges with dashed lines
for ee in edges:
ax.axvline(ee, ymax=0.75, ls='--', c='k')
# plot labels
for cc, ll in zip(centers, labels):
ax.annotate(ll, xy=(cc, 0.75), xytext=(0, 10),
xycoords=tform, textcoords='offset points',
ha='left', va='bottom', rotation=60)
# plot double-ended arrows
for start, stop in zip(edges[:-1], edges[1:]):
ax.annotate('', xy=(start, 0.75), xytext=(stop, 0.75),
xycoords=tform, textcoords=tform,
arrowprops=dict(arrowstyle='<->', lw=2, shrinkA=0, shrinkB=0))
# turn off spines and ticks on the top and right, so that they don't overlap
# with the labels
for sp in ('top', 'right'):
ax.spines[sp].set_visible(False)
ax.tick_params(top=False, right=False)
# rescale the y-axis so that the labels and arrows are positioned nicely relative
# to the line
ax.set_ylim(0, yvals.max() * 1.4)
这种方法需要更多的调整,以适应标签而不重叠彼此或轴脊。