Я мог бы возникнуть соблазн использовать 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)
Из комментариев, кажется, вы хотите, чтобы представить диапазон значений на оси времени, а не одной и вы хотите построить несколько рядов по одному и тому же набору осей (поэтому вы не хотите, чтобы какой-либо аспект аннотации менялся с 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)
Этот метод требует намного больше тонкой настройки в порядке для установки этикеток без наложения друг на друга или на оси.
возможно дубликат [Matplotlib: Добавить строки как пользовательские рентгеновские тики, но и сохранить существующую (числовой) отметьте метки? Альтернативы matplotlib.pyplot.annotate?] (Http://stackoverflow.com/questions/10615960/matplotlib-add-strings-as-custom-x-ticks-but-also-keep-existing-numeric-tick) – Evert