Selection area is not showing up in Tkinter

后端 未结 2 1306
隐瞒了意图╮
隐瞒了意图╮ 2020-12-22 06:01

I am developing an application which lets user Zoom a part of the graph based on their selection. I am able to get the initial x, y coordinates(x0, y0) and also

相关标签:
2条回答
  • 2020-12-22 06:37

    It works for me:

    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()
    
    0 讨论(0)
  • 2020-12-22 06:47

    You need to update these as the event changes:

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

    As is they will continually draw a fixed size rectangle at the coordinates (2.5, 5) with a width and height of 1.

    Similar to the question you were looking at something like this works.

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

    Notice that the rectangle dimensions are taken from the event. I added the guard to prevent mishaps where the event does not properly interpret the coordinate.


    @furas makes a good points in the comments, it is a good idea to initialize your coordinates to floats.

        self.x0 = 0.0
        self.y0 = 0.0
        self.x1 = 0.0
        self.y1 = 0.0
    
    0 讨论(0)
提交回复
热议问题