采用以下matplotlib
图形/图形,其中x轴为时间。
import numpy as np
import matplotlib.pyplot as plt
time = np.linspace(1500, 2000)
plt.plot(time, np.exp(time*0.01))
说我有一个标签列表,例如
myLabels = {1500:'Awful times', 1800:'Somewhat better times', 1930:'Bad again', 1990:'We are alright'}
标签应该间隔而不是点; Awful times
是[1500, 1800]
的标签。
我想以某种方式将这些标签中的信息添加到图中。 我的实际数字包含几个图表/时间序列,因此解决方案需要“系列独立”。我不知道什么看起来很好,以及如何做到这一点。我有一些想法
添加此类信息通常会采取什么措施?我将如何使用matplotlib
实现该功能?
答案 0 :(得分:5)
我可能想用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)
这种方法需要进行更多调整才能使标签适合而不会相互重叠或轴刺。
答案 1 :(得分:1)
要突出显示范围,您可以使用axhspan或axvspan在范围周围绘制框,并附上文本注释:
import numpy as np
import matplotlib.pyplot as plt
time = np.linspace(1500, 2000)
y=lambda t: np.exp(t*0.01)
plt.plot(time, y(time))
#use a list of tuples instead of a dictionary - it must be sorted!
myLabels = [(1500,'Awful times'), (1800,'Somewhat better times'), (1930,'Bad again'), (1990,'We are alright')]
colorLabels=['black', 'blue', 'red', 'green'] # set list of colors
for ix ,((xloc,txt),colr) in enumerate(zip(myLabels,colorLabels)):
# look ahead
if ix+1==len(myLabels):
xloc2=np.max(time)
else:
xloc2=myLabels[ix+1][0]
# draw a polygon between the lower and upper xrange, using our y function:
plt.axhspan(np.min(y(time)), y(xloc2),
xmin=(xloc-np.min(time))/(np.max(time)-np.min(time)),
xmax=(xloc2-np.min(time))/(np.max(time)-np.min(time)),
facecolor=colr, alpha=0.5)
# add a text arrow pointing to the center of the region of interest
plt.annotate(txt,xy=(np.mean([xloc,xloc2]),np.mean([y(xloc),y(xloc2)])),
xytext=(xloc*0.75+0.25*np.min(time),
y(xloc)*0.75+0.25*np.max(y(time))),
xycoords='data',
textcoords='data',
arrowprops=dict(arrowstyle="->"))
plt.show()
我使用该函数来设置矩形的顶部,但是如果有多个y
,则可以预先计算它们并取最大值或仅使用axvspan
默认y使用完整的y范围。