Matplotlib 小部件按钮在第一次点击并调用 on_clicked() 后无响应



我正在设置一个类,该类创建带有一些标记(X,Y(的线的简单XY图。

这个想法是为用户提供通过拖动点来更新线条的选项。

我添加了一个"重置"按钮,该按钮应该将行恢复到其原始值。

如果我拖动一个点并单击"重置"按钮,它可以正常工作,但如果尝试再次拖动一个点,按钮没有响应。

我对 matplotlib 小部件相当陌生,我一定错过了一些明显的东西......

请注意,我尝试使用不同的后端,我也尝试在笔记本单元格中使用(%matplotlib notebook(

这是我的"路径"类的代码:

import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import matplotlib as mpl
import numpy as np
from copy import copy
class Path(object):
def __init__(self, xcoords, ycoords):
    self.xcoords = xcoords
    self.ycoords = ycoords
    self.original_xcoords = copy(xcoords)
    self.original_ycoords = copy(ycoords)
    self.pind = None  # active point
    self.epsilon = 5  # max pixel distance
    # figure.subplot.right
    mpl.rcParams['figure.subplot.right'] = 0.8
    # set up a plot
    self.fig, self.ax1 = plt.subplots(1, 1, figsize=(9.0, 8.0), sharex=True)
    self.ax1.plot(self.xcoords, self.ycoords, 'k--', label='original')
    self.l, = self.ax1.plot(self.xcoords, self.ycoords,
        color='k', linestyle='none',
        marker='o', markersize=8)
    self.m, = self.ax1.plot(self.xcoords, self.ycoords, 'r-')
    self.ax1.set_yscale('linear')
    self.ax1.legend(loc=4, prop={'size': 10})
    self.axres = plt.axes([0.84, 0.8-((self.original_xcoords.shape[0])*0.05), 0.12, 0.02])
    self.bres = Button(self.axres, 'Test')
    self.bres.on_clicked(self.reset)
    self.fig.canvas.mpl_connect('button_press_event', self.button_press_callback)
    self.fig.canvas.mpl_connect('button_release_event', self.button_release_callback)
    self.fig.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
    plt.show()
def reset(self, event):
    """ Reset the values """
    self.xcoords = self.original_xcoords
    self.ycoords = self.original_ycoords
    self.l.set_xdata(self.xcoords)
    self.m.set_xdata(self.xcoords)
    self.l.set_ydata(self.ycoords)
    self.m.set_ydata(self.ycoords)
    plt.draw()
def button_press_callback(self, event):
    if event.inaxes is None:
        return
    if event.button != 1:
        return
    self.pind = self.get_ind_under_point(event)
def button_release_callback(self, event):
    if event.button != 1:
        return
    self.pind = None
def get_ind_under_point(self, event):
    """
       Get the index of the vertex under point if within epsilon tolerance
    """
    tinv = self.ax1.transData
    xr = np.reshape(self.xcoords, (np.shape(self.xcoords)[0], 1))
    yr = np.reshape(self.ycoords, (np.shape(self.ycoords)[0], 1))
    xy_vals = np.append(xr, yr, 1)
    xyt = tinv.transform(xy_vals)
    xt, yt = xyt[:, 0], xyt[:, 1]
    d = np.hypot(xt - event.x, yt - event.y)
    indseq, = np.nonzero(d == d.min())
    ind = indseq[0]
    if d[ind] >= self.epsilon:
        ind = None
    return ind
def motion_notify_callback(self, event):
    'on mouse movement'
    if self.pind is None:
        return
    if event.inaxes is None:
        return
    if event.button != 1:
        return
    self.ycoords[self.pind] = event.ydata
    self.xcoords[self.pind] = event.xdata
    self.l.set_xdata(self.xcoords)
    self.m.set_xdata(self.xcoords)
    self.l.set_ydata(self.ycoords)
    self.m.set_ydata(self.ycoords)
    self.fig.canvas.draw_idle()

x = np.array([1,2,3,4])
y = np.array([5, 6, 2, 3])
#%matplotlib notebook
A = Path(x, y)

这个问题的一个最小例子是:

import numpy as np
a = np.array([1,2,3])
b = a
b[1] = 1000
print(a)

它打印[1, 1000, 3],即使你似乎只修改了ba也被修改了。这是因为它们同一个数组。

因此,与其复制对同一数组的引用,不如复制数组,或仅使用其值。

import numpy as np
a = np.array([1,2,3])
b = np.copy(a)
b[1] = 1000
print(a)

在您的情况下,

self.xcoords[:] = self.original_xcoords
self.ycoords[:] = self.original_ycoords

self.xcoords = np.copy(self.original_xcoords)
self.ycoords = np.copy(self.original_ycoords)

长话短说:您应该更改重置功能:

self.xcoords = np.copy(self.original_xcoords)
self.ycoords = np.copy(self.original_ycoords)

如果简短一点,Python 中的所有变量都类似于指向对象的链接。当你写a = 5时,a得到对象"5"的链接,当你写b = a时,b得到链接到"5"作为a。同样的情况也发生在您的self.coordsself.original_coords上。您必须复制它们才能使它们链接到的不同对象。它们在第一次调用 reset(( 函数后链接到同一对象。你在那里保存了错误的坐标,所以从这一刻起,你的self.xcoordsself.original_coords对象链接到同一个对象

最新更新