我正在开发一个应用程序,它允许用户根据他们的选择缩放图形的一部分。我能够得到初始的x,y坐标(x0, y0)
以及最终的x,y坐标(x1, y1)
。但完全无能为什么选择区域没有出现。
from Tkinter import *
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
graph = Figure(figsize=(5,4), dpi=100)
ax = graph.add_subplot(111)
plot = ax.plot([1,2,3,4],[5,6,2,8])
canvas = FigureCanvasTkAgg(graph, master=root)
canvas.show()
canvas.get_tk_widget().grid(column=2, row=1, rowspan=2, sticky=(N, S, E, W))
class Zoom(object):
def __init__(self):
self.graph = Figure(figsize=(5,4), dpi=100)
self.ax = graph.add_subplot(111)
self.rect = ax.patch
self.rect.set_facecolor('green')
self.ax.plot([1,2,3,4],[5,6,2,8])
self.is_pressed = False
self.x0 = None
self.y0 = None
self.x1 = None
self.y1 = None
self.aid = graph.canvas.mpl_connect('button_press_event', self.on_press)
self.bid = graph.canvas.mpl_connect('button_release_event', self.on_release)
self.cid = graph.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
print 'press'
self.is_pressed = True
self.x0 = event.xdata
self.y0 = event.ydata
print(self.x1, self.x0)
print(self.y1, self.y0)
def on_motion(self, event):
if self.is_pressed is True:
print 'panning'
self.x1 = event.xdata
self.y1 = event.ydata
print(self.x1, self.x0)
print(self.y1, self.y0)
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print 'release'
self.is_pressed = False
self.x1 = event.xdata
self.y1 = event.ydata
print(self.x1, self.x0)
print(self.y1, self.y0)
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
my_object = Zoom()
root.mainloop()
我从这个问题中获得了帮助Matplotlib: draw a selection area in the shape of a rectangle with the mouse 我得到的输出是
press
(0.0, 1.4007056451612905)
(0.0, 6.9296116504854366)
panning
(1.4007056451612905, 1.4007056451612905)
(6.8932038834951452, 6.9296116504854366)
panning
(None, 1.4007056451612905)
(None, 6.9296116504854366)
panning
(None, 1.4007056451612905)
(None, 6.9296116504854366)
release
(None, 1.4007056451612905)
(None, 6.9296116504854366)
答案 0 :(得分:2)
您需要在事件发生变化时更新这些内容:
def on_motion(self, event):
if self.is_pressed is True:
self.x1 = event.xdata
self.y1 = event.ydata
self.rect.set_width(1)
self.rect.set_height(1)
self.rect.set_xy((2.5, 5))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print 'release'
self.is_pressed = False
self.x1 = event.xdata
self.y1 = event.ydata
self.rect.set_width(1)
self.rect.set_height(1)
self.rect.set_xy((2.5, 5))
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
他们将在坐标(2.5,5)处连续绘制一个固定大小的矩形,宽度和高度为1.
类似于你正在研究的问题。
def on_press(self, event):
print('press')
self.is_pressed = True
self.x0 = event.xdata
self.y0 = event.ydata
def on_motion(self, event):
self.x1, self.y1 = event.xdata, event.ydata
if (self.is_pressed is True and
self.x1 is not None and
self.y1 is not None):
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print('release')
self.is_pressed = False
self.x1, self.y1 = event.xdata, event.ydata
try:
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
except TypeError:
if (self.x1 is None or self.y1 is None):
return
else:
raise
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
请注意,矩形尺寸取自事件。我添加了防护装置,以防止在事件无法正确解释坐标的情况下发生意外。
@furas在评论中提出了一个很好的观点,将坐标初始化为浮点数是个好主意。
self.x0 = 0.0
self.y0 = 0.0
self.x1 = 0.0
self.y1 = 0.0
答案 1 :(得分:2)
它对我有用:
from Tkinter import *
from matplotlib.figure import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
graph = Figure(figsize=(5,4), dpi=100)
ax = graph.add_subplot(111)
plot = ax.plot([1,2,3,4],[5,6,2,8])
canvas = FigureCanvasTkAgg(graph, master=root)
canvas.show()
canvas.get_tk_widget().grid(column=2, row=1, rowspan=2, sticky=(N, S, E, W))
class Zoom(object):
def __init__(self):
self.graph = Figure(figsize=(5,4), dpi=100)
self.ax = graph.add_subplot(111)
# should be Rectangle((0,0),0,0)
self.rect = Rectangle((10,10),100,100)
self.ax.add_patch(self.rect)
self.ax.plot([1,2,3,4],[5,6,2,8])
self.is_pressed = False
self.x0 = 0.0
self.y0 = 0.0
self.x1 = 0.0
self.y1 = 0.0
self.aid = graph.canvas.mpl_connect('button_press_event', self.on_press)
self.bid = graph.canvas.mpl_connect('button_release_event', self.on_release)
self.cid = graph.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
self.is_pressed = True
if event.xdata is not None and event.ydata is not None:
self.x0, self.y0 = event.xdata, event.ydata
print 'press:', self.x0, self.y0
# only remove old rectangle
self.rect.set_width(0)
self.rect.set_height(0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
# color and linestyle for future motion
self.rect.set_facecolor('red')
self.rect.set_linestyle('dashed')
def on_motion(self, event):
if self.is_pressed:
if event.xdata is not None and event.ydata is not None:
self.x1, self.y1 = event.xdata, event.ydata
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
print 'rect:', self.x0, self.y0, self.x1, self.y1, (self.x1-self.x0), (self.y1-self.y0)
def on_release(self, event):
self.is_pressed = False
print 'release:', event.xdata, event.ydata
# change only color and linestyle
#self.rect.set_width(self.x1 - self.x0)
#self.rect.set_height(self.y1 - self.y0)
#self.rect.set_xy((self.x0, self.y0))
self.rect.set_facecolor('blue')
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
my_object = Zoom()
root.mainloop()