我正在建立一个类,该类创建带有一些标记(X,Y)的直线的简单XY图。
这个想法是让用户可以选择通过拖动点来更新线。
我添加了一个“重置”按钮,该按钮应该将行恢复为原始值。
如果我拖动一个点并单击“重置”按钮,则可以正常工作,但是如果 尝试再次拖动一个点,按钮无响应。
我对matplotlib小部件还很陌生,我肯定缺少明显的东西...
请注意,我尝试使用不同的后端,也尝试使用(%matplotlib notebook
)在笔记本单元内部
这是我的“ Path”类的代码:
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)
答案 0 :(得分:1)
问题的最小示例是:
import numpy as np
a = np.array([1,2,3])
b = a
b[1] = 1000
print(a)
它会打印[1, 1000, 3]
,即使您似乎只修改了b
,a
也被修改了。这是因为它们 是相同的数组。
因此,与其复制对同一数组的引用,不如复制该数组或仅使用其值。
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)
答案 1 :(得分:0)
长话短说:您应该更改重置功能:
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.coords
和self.original_coords
也会发生相同的情况。您必须复制它们以使它们链接到不同的对象。在第一次调用reset()函数之后,它们链接到同一对象。
您在此处保存了错误的坐标,因此自此以来,您的self.xcoords
和self.original_coords
对象已链接到同一对象