使用 matplotlib 在单击时绘制点的问题

Problem with plotting a dot on click with matplotlib

我刚开始学习python和交互式绘图,欢迎任何帮助。

这段代码的目的是点击十个按钮之一来选择-5到5之间的一个值,然后通过点击主轴上的任意位置显示这个值,然后从这些点生成电场图.问题是,当我单击任何按钮时,图形中间会绘制一个点。 如果我正确理解发生了什么,onclick 函数会将每个按钮的轴解释为主轴的一部分。 有人可以帮我解决这个问题吗?


import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.widgets import Button

fig, ax= plt.subplots(figsize=(8,8))

axButton1=plt.axes([0,0.90,0.1,0.07])
btn1= Button(axButton1,label='-5')

axButton2=plt.axes([0.1,0.90,0.1,0.07])
btn2= Button(axButton2,label='-4')

axButton3=plt.axes([0.2,0.90,0.1,0.07])
btn3= Button(axButton3,label='-3')

axButton4=plt.axes([0.3,0.90,0.1,0.07])
btn4= Button(axButton4,label='-2')

axButton5=plt.axes([0.4,0.90,0.1,0.07])
btn5= Button(axButton5,label='-1')

axButton6=plt.axes([0.5,0.90,0.1,0.07])
btn6= Button(axButton6,label='1')

axButton7=plt.axes([0.6,0.90,0.1,0.07])
btn7= Button(axButton7,label='2')

axButton8=plt.axes([0.7,0.90,0.1,0.07])
btn8= Button(axButton8,label='3')

axButton9=plt.axes([0.8,0.90,0.1,0.07])
btn9= Button(axButton9,label='4')

axButton10=plt.axes([0.9,0.90,0.1,0.07])
btn10= Button(axButton10,label='5')

q=0

def neg5(event):
    global q
    q=-5
    
btn1.on_clicked(neg5)

def neg4(event):
    global q
    q=-4
    
btn2.on_clicked(neg4)

def neg3(event):
    global q
    q=-3
    
btn3.on_clicked(neg3)

def neg2(event):
    global q
    q=-2
    
btn4.on_clicked(neg2)

def neg1(event):
    global q
    q=-1
    
btn5.on_clicked(neg1)

def pos1(event):
    global q
    q=1
    
btn6.on_clicked(pos1)

def pos2(event):
    global q
    q=2
    
btn7.on_clicked(pos2)

def pos3(event):
    global q
    q=3
    
btn8.on_clicked(pos3)

def pos4(event):
    global q
    q=4
    
btn9.on_clicked(pos4)

def pos5(event):
    global q
    q=5
    
btn10.on_clicked(pos5)


plt.subplots_adjust(top=0.77, bottom=0.05)
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])

charges=[]

def onclick(event):
    global charges
    M=(event.xdata, event.ydata)
    print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
          (event.button, event.x, event.y, event.xdata, event.ydata))
    charges.append(M)
    print(charges)
    ax.add_artist(mpl.patches.Circle(M, 0.3, color='r', ec='black', lw=1.5))
    ax.text(event.xdata,event.ydata,str(q), size='20', color='w', zorder=2, horizontalalignment = 'center', verticalalignment = 'center')
    fig.canvas.draw()
    


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

plt.show()

欢迎,欢迎来到 Python。

我确定我没有最佳答案,因为我没有使用过 canvas.mpl_connect,但我相信我有一个适合您的解决方案。

将所有 onclick(events) 放在 if 语句下,这样单击按钮(子图,而不是主坐标轴)就不会触发所有内容:

def onclick(event):
    if issubclass(event.inaxes.__class__, mpl.axes.SubplotBase):
        global charges
        M=(event.xdata, event.ydata)
        print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
              (event.button, event.x, event.y, event.xdata, event.ydata))
        charges.append(M)
        print(charges)
        ax.add_artist( mpl.patches.Circle(M, 0.3, color='r', ec='black', lw=1.5) )
        ax.text(event.xdata,event.ydata,str(q), size='20', color='w', zorder=2, horizontalalignment = 'center', verticalalignment = 'center')
        fig.canvas.draw()

您可以使用 event.inaxes 检查事件的来源。 这是一个示例实现。我还使用工厂清理了 q setter 函数。类似的东西也适用于按钮的创建,然后你可以在循环中做所有事情而不需要太多重复。我鼓励你尝试一下。

import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.widgets import Button

fig, ax= plt.subplots(figsize=(8,8))

axButton1=plt.axes([0,0.90,0.1,0.07])
btn1= Button(axButton1,label='-5')

axButton2=plt.axes([0.1,0.90,0.1,0.07])
btn2= Button(axButton2,label='-4')

axButton3=plt.axes([0.2,0.90,0.1,0.07])
btn3= Button(axButton3,label='-3')

axButton4=plt.axes([0.3,0.90,0.1,0.07])
btn4= Button(axButton4,label='-2')

axButton5=plt.axes([0.4,0.90,0.1,0.07])
btn5= Button(axButton5,label='-1')

axButton6=plt.axes([0.5,0.90,0.1,0.07])
btn6= Button(axButton6,label='1')

axButton7=plt.axes([0.6,0.90,0.1,0.07])
btn7= Button(axButton7,label='2')

axButton8=plt.axes([0.7,0.90,0.1,0.07])
btn8= Button(axButton8,label='3')

axButton9=plt.axes([0.8,0.90,0.1,0.07])
btn9= Button(axButton9,label='4')

axButton10=plt.axes([0.9,0.90,0.1,0.07])
btn10= Button(axButton10,label='5')

q=0

#generator function for q setters
def valueSetterFuncGen(val): 
    def func(event):
        global q
        q = val
    return func

btn1.on_clicked(valueSetterFuncGen(-5))
btn2.on_clicked(valueSetterFuncGen(-4))
btn3.on_clicked(valueSetterFuncGen(-3))
btn4.on_clicked(valueSetterFuncGen(-2))
btn5.on_clicked(valueSetterFuncGen(-1))
btn6.on_clicked(valueSetterFuncGen(1))
btn7.on_clicked(valueSetterFuncGen(2))
btn8.on_clicked(valueSetterFuncGen(3))
btn9.on_clicked(valueSetterFuncGen(4))
btn10.on_clicked(valueSetterFuncGen(5))


plt.subplots_adjust(top=0.77, bottom=0.05)
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])

charges=[]

def onclick(event):
    if event.inaxes==ax:
        global charges
        M=(event.xdata, event.ydata)
        print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f, ax = %s' %
              (event.button, event.x, event.y, event.xdata, event.ydata, event.inaxes==ax))
        charges.append(M)
        print(charges)
        ax.add_artist(mpl.patches.Circle(M, 0.3, color='r', ec='black', lw=1.5))
        ax.text(event.xdata,event.ydata,str(q), size='20', color='w', zorder=2, horizontalalignment = 'center', verticalalignment = 'center')
        fig.canvas.draw()
    


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

plt.show()

---剧透---

这是解决方案

import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.widgets import Button

fig, ax= plt.subplots(figsize=(8,8))


#factory function for q setters
def valueSetterFuncGen(val): 
    def func(event):
        global q
        q = val
    return func


btns = []
for i in range(10):
    axButton_=plt.axes([i/10.,0.90,0.1,0.07])
    l = ''
    if i-5 < 0:
        l = int(i-5)
    else:
        l = int(i-4)
    # if we are already looping, a button factory would not make things easier 
    btn_= Button(axButton_,label=str(l))
    btn_.on_clicked(valueSetterFuncGen(l))
    btns.append(btn_)

plt.subplots_adjust(top=0.77, bottom=0.05)
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
q=0
charges=[]

def onclick(event):
    if event.inaxes==ax:
        global charges
        M=(event.xdata, event.ydata)
        print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f, ax = %s' %
              (event.button, event.x, event.y, event.xdata, event.ydata, event.inaxes==ax))
        charges.append(M)
        print(charges)
        ax.add_artist(mpl.patches.Circle(M, 0.3, color='r', ec='black', lw=1.5))
        ax.text(event.xdata,event.ydata,str(q), size='20', color='w', zorder=2, horizontalalignment = 'center', verticalalignment = 'center')
        fig.canvas.draw()
    


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

plt.show()