简体   繁体   English

Matplotlib事件并重新绘制

[英]Matplotlib event and replotting

I want to be able to create a plot, press one button or another depending on what the plot shows, and then plot the following object. 我希望能够创建一个图,根据图显示的内容按下一个或另一个按钮,然后绘制以下对象。 However, I am having some trouble wih it: it seems I can't make it "wait" untill a button is pressed. 但是,我遇到了一些麻烦:似乎我无法使其“等待”,直到按下按钮为止。 Also, I am wondering if it would be possible to pass some parameters to the press_event, like a path to save something. 另外,我想知道是否可以将某些参数传递给press_event,例如保存内容的路径。

Here is the scheme of the program in case it helps. 如果有帮助,这里是程序的方案。 Thanks a lot in advance! 在此先多谢!

# event definition
def ontype(event):
    if event.key == '1':
        do stuff 1
        plt.savefig(...)
        plt.clf()
    elif event.key == '2':
        do stuff 2
        plt.savefig(...)
        plt.clf()
    elif event.key == '3':
        do stuff 3
        plt.savefig(...)
        plt.clf()

# main program
...stuff
create figure
plt.show()
plt.gcf().canvas.mpl_connect('key_press_event',ontype)

You must call plt.gcf().canvas.mpl_connect('key_press_event',ontype) before plt.show() . 您必须在plt.show()之前调用plt.gcf().canvas.mpl_connect('key_press_event',ontype) plt.show() In non-interactive mode, the execution waits at plt.show() until the plot-window is closed. 在非交互模式下,执行在plt.show()处等待,直到关闭绘图窗口。

import pylab as plt

# event definition
def ontype(event):
    if event.key == '1':
        print "1"
    elif event.key == '2':
        print "2"
    elif event.key == '3':
        print "3"

# main program
plt.plot([1,6,3,8,7])
plt.gcf().canvas.mpl_connect('key_press_event',ontype)
plt.show()

Alternatively, replace in your sample plt.show() to plt.ion() , which enables interactive mode. 或者,将示例plt.show()替换为plt.ion() ,以启用交互模式。 But it depends on your specific needs which solution you prefer. 但这取决于您的特定需求,您喜欢哪种解决方案。

Edit 编辑

New example using Tkinter 使用Tkinter的新示例

import random
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure

try:
    import Tkinter as Tk
except ImportError:
    import tkinter as Tk
import tkMessageBox

class PlotClassifier(Tk.Tk):
    def __init__(self, plot_generator, arguments, classes, classification_callback, *args, **kwargs):
        Tk.Tk.__init__(self, *args, **kwargs)
        self.title("Plot classifier, working on %i plots" % len(arguments))
        #self.label = Tk.Label(text="Plot classifier, working on %i plots" % len(arguments))
        #self.label.pack(padx=10, pady=10)
        self._plot_generator = plot_generator
        self._arguments = arguments
        self._classes = [str(x) for x in classes]
        self._classification_callback = classification_callback
        self._setup_gui()

    def _setup_gui(self):
        #self.columnconfigure(0, minsize=100, weight=2)
        #self.columnconfigure(1, minsize=500, weight=8)
        f = Figure()
        self._ax = f.add_subplot(111)
        buttons_frame = Tk.Frame(self)
        buttons_frame.pack(side=Tk.TOP, fill=Tk.BOTH, expand=True)
        buttons_class = []
        for i, cls in enumerate(self._classes):
            buttons_class.append(Tk.Button(master=buttons_frame, text=cls, 
                                           command=lambda x=i: self.button_classification_callback(self._current_args, x)))
            buttons_class[-1].pack(side=Tk.LEFT)
        button_quit = Tk.Button(master=buttons_frame, text='Quit', command=self.destroy)
        button_quit.pack(side=Tk.RIGHT) #.grid(row=0,column=0)

        self._canvas = FigureCanvasTkAgg(f, master=self)
        self._canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=0, column=1, rowspan=3) #
        self._canvas.show()

        toolbar = NavigationToolbar2TkAgg( self._canvas, self )
        toolbar.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=3, column=1) #
        toolbar.update()

    def button_classification_callback(self, args, class_idx):
        self._classification_callback(args, self._classes[class_idx])
        self.classify_next_plot()

    def classify_next_plot(self):
        try:
            self._current_args = self._arguments.pop(0)
            self._ax.cla()
            self._plot_generator(self._ax, *self._current_args)
            self._canvas.draw()
        except IndexError:
            tkMessageBox.showinfo("Complete!", "All plots were classified")
            self.destroy()        

def create_plot(ax, factor):
    ax.plot([(i*factor) % 11 for i in range(100)])

def announce_classification(arguments, class_):
    print arguments, class_

if __name__ == "__main__":
    classes = ["Class %i"%i for i in range(1, 6)]
    arguments_for_plot = [[random.randint(1,10)] for x in range(10)]
    root = PlotClassifier(create_plot, arguments_for_plot, classes, classification_callback=announce_classification)
    root.after(50, root.classify_next_plot)
    root.mainloop()

The class takes as arguments: * a callback to create each plot * a list of lists of arguments for each plot to generate (might each be an empty list) * a list of class-names. 该类使用以下参数作为参数:*创建每个图的回调*每个图生成的参数列表(可能每个列表为空列表)*类名列表。 For each class, a button is created * a callback that is called each time a classification has been performed 对于每个类,都会创建一个按钮*每次执行分类时都会调用的回调

Any feedback would be appreciated. 对于任何反馈,我们都表示感谢。

* EDIT 2 * For your comment, a slightly modified version. * 编辑2 *为您的评论,略作修改的版本。 For every iteration of the loop, a new window is opened 对于循环的每次迭代,都会打开一个新窗口

import random
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure

try:
    import Tkinter as Tk
except ImportError:
    import tkinter as Tk
import tkMessageBox

class PlotClassifier(Tk.Tk):
    def __init__(self, plot_generator, arguments, classes, *args, **kwargs):
        Tk.Tk.__init__(self, *args, **kwargs)
        self.title("Plot classifier")
        self._plot_generator = plot_generator
        self._arguments = arguments
        self._classes = [str(x) for x in classes]
        self.class_ = None
        self._setup_gui()

    def _setup_gui(self):
        #self.columnconfigure(0, minsize=100, weight=2)
        #self.columnconfigure(1, minsize=500, weight=8)
        f = Figure()
        self._ax = f.add_subplot(111)
        buttons_frame = Tk.Frame(self)
        buttons_frame.pack(side=Tk.TOP, fill=Tk.X, expand=True)
        buttons_class = []
        for i, cls in enumerate(self._classes):
            buttons_class.append(Tk.Button(master=buttons_frame, text=cls, 
                                           command=lambda x=i: self.button_classification_callback(x)))
            buttons_class[-1].pack(side=Tk.LEFT)
        button_quit = Tk.Button(master=buttons_frame, text='Quit', command=self.destroy)
        button_quit.pack(side=Tk.RIGHT) #.grid(row=0,column=0)

        self._canvas = FigureCanvasTkAgg(f, master=self)
        self._canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=0, column=1, rowspan=3) #
        self._canvas.show()

        toolbar = NavigationToolbar2TkAgg( self._canvas, self )
        toolbar.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=3, column=1) #
        toolbar.update()

    def button_classification_callback(self, class_idx):
        self.class_ = self._classes[class_idx]
        self.destroy()

    def classify_plot(self):
        self._ax.cla()
        self._plot_generator(self._ax, *self._arguments)
        self._canvas.draw()
        self.mainloop()
        return self.class_

def create_plot(ax, factor):
    ax.plot([(i*factor) % 11 for i in range(100)])


if __name__ == "__main__":
    classes = ["Class %i"%i for i in range(1, 6)]
    arguments_for_plot = [[random.randint(1,10)] for x in range(10)]
    for args in arguments_for_plot:
        classifier = PlotClassifier(create_plot, args, classes)
        class_ = classifier.classify_plot()
        print args, class_
        if class_ is None:
            break

This helps to fit into your own for-loop, but you still have to give a function to do the plotting after the GUI was created. 这有助于适应您自己的for循环,但是在创建GUI之后,您仍然必须提供一个函数来进行绘图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM