"Interactive" figure in a GUI - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: "Interactive" figure in a GUI (/thread-27798.html) |
"Interactive" figure in a GUI - puje - Jun-22-2020 Hello I´ve written the code below, which creates a figure with two subplots. Each subplot has a "draggable line" that returns the x-value when released. Is it possible to implement this draggable line in a GUI using a framework such as Tkinter or PyQT? So far, I´ve only managed embed the plots and lines in a GUI but the "Interactive" part is lost. Any help is greatly appreciated import matplotlib.pyplot as plt import matplotlib.lines as lines import numpy as np import random class draggableline: def __init__(self, ax, XorY): self.ax = ax self.c = ax.get_figure().canvas self.XorY = XorY x = [XorY, XorY] y = [-1, 10] self.line = lines.Line2D(x, y, color='red', picker=5) self.ax.add_line(self.line) self.c.draw_idle() self.sid = self.c.mpl_connect('pick_event', self.clickonline) def clickonline(self, event): if event.artist == self.line: self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse) self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick) def followmouse(self, event): self.line.set_xdata([event.xdata, event.xdata]) self.c.draw_idle() def releaseonclick(self, event): self.XorY = self.line.get_xdata()[0] print (self.XorY) self.c.mpl_disconnect(self.releaser) self.c.mpl_disconnect(self.follower) class draggableline2: def __init__(self, ax2, XorY): self.ax2 = ax2 self.c = ax2.get_figure().canvas self.XorY = XorY x = [XorY, XorY] y = [-1, 10] self.line = lines.Line2D(x, y, color='red', picker=5) self.ax2.add_line(self.line) self.c.draw_idle() self.sid = self.c.mpl_connect('pick_event', self.clickonline) def clickonline(self, event): if event.artist == self.line: self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse) self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick) def followmouse(self, event): self.line.set_xdata([event.xdata, event.xdata]) self.c.draw_idle() def releaseonclick(self, event): self.XorY = self.line.get_xdata()[0] print (self.XorY) self.c.mpl_disconnect(self.releaser) self.c.mpl_disconnect(self.follower) fig, (ax, ax2) = plt.subplots(2) ax.plot([0, 1, 2, 3, 4, 5], [1, 1, 6, 4, 6, 2]) ax2.plot([0, 1, 2, 3, 4, 5], [1, 1, 2, 4, 2, 1]) Tline = draggableline(ax, 0.1) Tline2 = draggableline2(ax2, 0.1) plt.show() RE: "Interactive" figure in a GUI - Gribouillis - Jun-22-2020 In tkinter you can bind canvas items (such as lines) to events, such as a mouse click by using the canvas.tag_bind() method. From there you can implement dragging canvas items on the canvas. I haven't written such code for a long time but I know it is possible.
RE: "Interactive" figure in a GUI - puje - Jun-24-2020 I´ve updated the initial script with a modified version of Bryan-Oakley´s answer here stackoverflow.com/a/6789351/7432 It now has 2 canvas. 1 with the draggable rectangle and 1 with the plot. I would like the rectangle to be dragged along the x-axis on the plot if that is possible? import tkinter as tk # python 3 # import Tkinter as tk # python 2 import numpy as np from matplotlib.backends.backend_tkagg import ( FigureCanvasTkAgg, NavigationToolbar2Tk) # Implement the default Matplotlib key bindings. from matplotlib.backend_bases import key_press_handler from matplotlib.figure import Figure class Example(tk.Frame): """Illustrate how to drag items on a Tkinter canvas""" def __init__(self, parent): tk.Frame.__init__(self, parent) fig = Figure(figsize=(5, 4), dpi=100) t = np.arange(0, 3, .01) fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t)) #create a canvas self.canvas = tk.Canvas(width=200, height=300) self.canvas.pack(fill="both", expand=True) canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea. canvas.draw() canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) # this data is used to keep track of an # item being dragged self._drag_data = {"x": 0, "y": 0, "item": None} # create a movable object self.create_token(100, 150, "black") # add bindings for clicking, dragging and releasing over # any object with the "token" tag self.canvas.tag_bind("token", "<ButtonPress-1>", self.drag_start) self.canvas.tag_bind("token", "<ButtonRelease-1>", self.drag_stop) self.canvas.tag_bind("token", "<B1-Motion>", self.drag) def create_token(self, x, y, color): """Create a token at the given coordinate in the given color""" self.canvas.create_rectangle( x - 5, y - 100, x + 5, y + 100, outline=color, fill=color, tags=("token",), ) def drag_start(self, event): """Begining drag of an object""" # record the item and its location self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0] self._drag_data["x"] = event.x self._drag_data["y"] = event.y def drag_stop(self, event): """End drag of an object""" # reset the drag information self._drag_data["item"] = None self._drag_data["x"] = 0 self._drag_data["y"] = 0 def drag(self, event): """Handle dragging of an object""" # compute how much the mouse has moved delta_x = event.x - self._drag_data["x"] delta_y = 0 # move the object the appropriate amount self.canvas.move(self._drag_data["item"], delta_x, delta_y) # record the new position self._drag_data["x"] = event.x self._drag_data["y"] = event.y if __name__ == "__main__": root = tk.Tk() Example(root).pack(fill="both", expand=True) root.mainloop() |