【问题标题】:How to interactively find and annotate local max (peaks) in matplotlib?如何在 matplotlib 中以交互方式查找和注释局部最大值(峰值)?
【发布时间】:2013-10-16 08:38:17
【问题描述】:

我正在尝试分析一些光谱以查找光谱峰值,我编写了这个简单的代码,通过单击我想要查找的峰值前后来查找两个 X 数据之间的最大 Y 值(峰值)。这可行,我可以得到峰值的坐标,但我想自动注释找到的峰值。

import matplotlib.pyplot as plt 
X=[1,2,3,4,5,6,7,8,9,10]
Y=[1,1,1,2,10,2,1,1,1,1]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(X,Y,label="prova") #plot the function
#plt.legend(loc=1, ncol=1, shadow=True)
plt.xlim(min(X) * 0.9, max(X) * 1.1)
plt.ylim(min(Y) * 0.9, max(Y) * 1.1)
plt.ylabel(r'Y axis')
plt.xlabel(r'X axis')
Diz=dict(zip(X,Y)) #create a dictionary that associate X with Y
Interval=[] #interval where the user search for peaks
PeaksList=[] #list of peaks found
def onclick(event):
    print 'First limit at =%f'%(event.xdata)
    Interval.append(event.xdata)
    if len(Interval)%2==0:
        a=Interval[-2]       
        b=Interval[-1]    
        if b<a: #if the user select first the highest value these statements filp it!
            A=b
            B=a
        else:
            A=a
            B=b
      #find the max Y value: the peak!
        peakY=0 #max Y value
        piccoX=0 #value of the X associate to the peak
        for i in [ j for j in X if A<j<B] :
            if Diz[i]>peakY:
                peakY=Diz[i]
                piccoX=i
        print "Interval: %f - %f  Peak at: %f " %(a,b,piccoX)
        PeaksList.append([piccoX,peakY])
        ax.annotate("picco", xy=(piccoX,peakY),  xycoords='data',
                xytext=(-50, 30), textcoords='offset points',
                arrowprops=dict(arrowstyle="->")
                )      


plt.show()         
cid = fig.canvas.mpl_connect('button_press_event', onclick)

这是我第二次点击后想要的:

【问题讨论】:

  • 您要查找并注释所有最大值吗?
  • @Jakob 我想注释我在点击之前和之后发现的峰值,我在问题中是如何写的。尝试代码以了解!谢谢。

标签: python-2.7 matplotlib data-analysis


【解决方案1】:

您必须重新绘制图形 - 只需将 plt.draw 添加到 onclick 方法即可。
此外,您必须在显示图形之前连接事件。 当然,这里您的注释文本是“picco”而不是“5”。

试试:

import matplotlib.pyplot as plt 
X=[1,2,3,4,5,6,7,8,9,10]
Y=[1,1,1,2,10,2,1,1,1,1]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(X,Y,label="prova") #plot the function
#plt.legend(loc=1, ncol=1, shadow=True)
plt.xlim(min(X) * 0.9, max(X) * 1.1)
plt.ylim(min(Y) * 0.9, max(Y) * 1.1)
plt.ylabel(r'Y axis')
plt.xlabel(r'X axis')
Diz=dict(zip(X,Y)) #create a dictionary that associate X with Y
Interval=[] #interval where the user search for peaks
PeaksList=[] #list of peaks found
def onclick(event):
    print 'First limit at =%f'%(event.xdata)
    Interval.append(event.xdata)
    if len(Interval)%2==0:
        a=Interval[-2]       
        b=Interval[-1]    
        if b<a: #if the user select first the highest value these statements filp it!
            A=b
            B=a
        else:
            A=a
            B=b
      #find the max Y value: the peak!
        peakY=0 #max Y value
        piccoX=0 #value of the X associate to the peak
        for i in [ j for j in X if A<j<B] :
            if Diz[i]>peakY:
                peakY=Diz[i]
                piccoX=i
        print "Interval: %f - %f  Peak at: %f " %(a,b,piccoX)
        PeaksList.append([piccoX,peakY])
        ax.annotate("picco", xy=(piccoX,peakY),  xycoords='data',
                xytext=(-50, 30), textcoords='offset points',
                arrowprops=dict(arrowstyle="->")
                )
        plt.draw()

cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()     

也许视觉上更吸引人(使用 spanselector):

import matplotlib.pyplot as plt 
from matplotlib.widgets import SpanSelector
X=[1,2,3,4,5,6,7,8,9,10]
Y=[1,1,1,2,10,2,1,1,1,1]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(X,Y,label="prova") #plot the function
#plt.legend(loc=1, ncol=1, shadow=True)
plt.xlim(min(X) * 0.9, max(X) * 1.1)
plt.ylim(min(Y) * 0.9, max(Y) * 1.1)
plt.ylabel(r'Y axis')
plt.xlabel(r'X axis')
Diz=dict(zip(X,Y)) #create a dictionary that associate X with Y
Interval=[] #interval where the user search for peaks
PeaksList=[] #list of peaks found
def onclick(xmin, xmax):
    print 'Interval: {0} - {1}'.format(xmin,xmax)
    peakY=0 #max Y value
    piccoX=0 #value of the X associate to the peak
    for i in [ j for j in X if xmin<j<xmax] :
        if Diz[i]>peakY:
            peakY=Diz[i]
            piccoX=i
    print "Peak at: %f " % piccoX
    PeaksList.append([piccoX,peakY])
    ax.annotate("picco", xy=(piccoX,peakY),  xycoords='data',
            xytext=(-50, 30), textcoords='offset points',
            arrowprops=dict(arrowstyle="->"))
    plt.draw()

span = SpanSelector(ax, onclick, 'horizontal', useblit=True,
                    rectprops=dict(alpha=0.5, facecolor='blue') )
plt.show()

【讨论】:

  • 非常感谢 Jakob,我会稍等片刻,然后我会接受答案。谢谢!
  • 我在答案中添加了 SpanSelector 版本。
  • 感谢它的工作,但我有以下错误:AttributeError: 'FigureCanvasMac' object has no attribute 'copy_from_bbox' 我在我的 OSX 中看不到矩形。
  • 对不起,我没有 OSX,所以我没有用不同的后端测试这个。有一个相关的问题stackoverflow.com/q/13216520/2870069 正是在处理这个问题。也许答案可以帮助你。
  • @Ralf 是的,它应该适用于所有交互式后端,包括笔记本 (nbagg) 后端。只需在开头%matplotlib notebook 添加以下行。请注意,inline 后端不是交互式的,因此在这里不起作用。
猜你喜欢
  • 2014-05-15
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 2013-01-24
  • 1970-01-01
  • 2021-09-12
相关资源
最近更新 更多