选择区域未显示在Tkinter中

时间:2014-07-15 01:29:10

标签: python matplotlib tkinter

我正在开发一个应用程序,它允许用户根据他们的选择缩放图形的一部分。我能够得到初始的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)

2 个答案:

答案 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()