首页 文章

有没有办法分离matplotlib图,以便计算可以继续?

提问于
浏览
209

在Python解释器中的这些指令之后,获得一个带有绘图的窗口:

from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code

不幸的是,我不知道如何在程序进行进一步计算时继续以交互方式探索由 show() 创建的图形 .

有可能吗?有时计算很长,如果他们在检查中间结果期间继续进行计算会有所帮助 .

18 回答

  • 26

    使用 matplotlib 's calls that won' t块:

    使用 draw()

    from matplotlib.pyplot import plot, draw, show
    plot([1,2,3])
    draw()
    print 'continue computation'
    
    # at the end call show to ensure window won't close.
    show()
    

    使用交互模式:

    from matplotlib.pyplot import plot, ion, show
    ion() # enables interactive mode
    plot([1,2,3]) # result shows immediatelly (implicit draw())
    
    print 'continue computation'
    
    # at the end call show to ensure window won't close.
    show()
    
  • 3

    IMPORTANT :只是为了说清楚 . 我假设命令在 .py 脚本中,并且使用例如调用脚本来调用脚本 . 从控制台 python script.py .

    一个适合我的简单方法是:

    • 在show: plt.show(block = False) 中使用block = False

    • 使用.py脚本的 another show() at the end .


    Example of script.py 文件:

    plt.imshow(*something*)                                                               
    plt.colorbar()                                                                             
    plt.xlabel("true ")                                                                   
    plt.ylabel("predicted ")                                                              
    plt.title(" the matrix")  
    
    # Add block = False                                           
    plt.show(block = False)
    
    # OTHER CALCULATIONS AND CODE
    
    # the next is the last line of my script
    plt.show()
    

  • 1

    好吧,我很难搞清楚非阻塞命令......但最后,我设法重做“Cookbook/Matplotlib/Animations - Animating selected plot elements”示例,因此它适用于线程(并通过全局变量或通过多进程传递线程之间的数据 Pipe )在Ubuntu 10.04上的Python 2.6.5上 .

    该脚本可以在这里找到:Animating_selected_plot_elements-thread.py - 否则粘贴在下面(评论较少)供参考:

    import sys
    import gtk, gobject
    import matplotlib
    matplotlib.use('GTKAgg')
    import pylab as p
    import numpy as nx 
    import time
    
    import threading 
    
    
    
    ax = p.subplot(111)
    canvas = ax.figure.canvas
    
    # for profiling
    tstart = time.time()
    
    # create the initial line
    x = nx.arange(0,2*nx.pi,0.01)
    line, = ax.plot(x, nx.sin(x), animated=True)
    
    # save the clean slate background -- everything but the animated line
    # is drawn and saved in the pixel buffer background
    background = canvas.copy_from_bbox(ax.bbox)
    
    
    # just a plain global var to pass data (from main, to plot update thread)
    global mypass
    
    # http://docs.python.org/library/multiprocessing.html#pipes-and-queues
    from multiprocessing import Pipe
    global pipe1main, pipe1upd
    pipe1main, pipe1upd = Pipe()
    
    
    # the kind of processing we might want to do in a main() function,
    # will now be done in a "main thread" - so it can run in
    # parallel with gobject.idle_add(update_line)
    def threadMainTest():
        global mypass
        global runthread
        global pipe1main
    
        print "tt"
    
        interncount = 1
    
        while runthread: 
            mypass += 1
            if mypass > 100: # start "speeding up" animation, only after 100 counts have passed
                interncount *= 1.03
            pipe1main.send(interncount)
            time.sleep(0.01)
        return
    
    
    # main plot / GUI update
    def update_line(*args):
        global mypass
        global t0
        global runthread
        global pipe1upd
    
        if not runthread:
            return False 
    
        if pipe1upd.poll(): # check first if there is anything to receive
            myinterncount = pipe1upd.recv()
    
        update_line.cnt = mypass
    
        # restore the clean slate background
        canvas.restore_region(background)
        # update the data
        line.set_ydata(nx.sin(x+(update_line.cnt+myinterncount)/10.0))
        # just draw the animated artist
        ax.draw_artist(line)
        # just redraw the axes rectangle
        canvas.blit(ax.bbox)
    
        if update_line.cnt>=500:
            # print the timing info and quit
            print 'FPS:' , update_line.cnt/(time.time()-tstart)
    
            runthread=0
            t0.join(1)   
            print "exiting"
            sys.exit(0)
    
        return True
    
    
    
    global runthread
    
    update_line.cnt = 0
    mypass = 0
    
    runthread=1
    
    gobject.idle_add(update_line)
    
    global t0
    t0 = threading.Thread(target=threadMainTest)
    t0.start() 
    
    # start the graphics update thread
    p.show()
    
    print "out" # will never print - show() blocks indefinitely!
    

    希望这有助于某人,
    干杯!

  • 3

    在许多情况下,它是 more convenient til save the image 作为硬盘驱动器上的.png文件 . 原因如下:

    Advantages:

    • 您可以打开它,查看它并在此过程中随时关闭它 . 当您的应用程序长时间运行时,这非常方便 .

    • 没有任何东西弹出,你不会被迫打开窗户 . 当您处理许多数字时,这尤其方便 .

    • 您的图像可供以后参考,关闭图形窗口时不会丢失 .

    Drawback:

    • 我唯一能想到的就是你必须去查找文件夹并自己打开图像 .
  • 0

    尝试

    from matplotlib.pyplot import *
    plot([1,2,3])
    show(block=False)
    # other code
    # [...]
    
    # Put
    show()
    # at the very end of your script
    # to make sure Python doesn't bail out
    # before you finished examining.
    

    show() documentation说:

    在非交互模式下,显示所有数字并阻止,直到数字关闭;在交互模式下,除非在从非交互模式更改为交互模式之前创建数字(不推荐),否则它无效 . 在这种情况下,它显示数字但不阻止 . 单个实验关键字参数block可以设置为True或False以覆盖上述阻塞行为 .

  • 10

    使用关键字“block”来覆盖阻止行为,例如

    from matplotlib.pyplot import show, plot
    
    plot(1)  
    show(block=False)
    
    # your code
    

    继续你的代码 .

  • 115

    在我看来,这个帖子中的答案提供的方法不适用于每个系统以及动画等更复杂的情况 . 我建议在下面的线程中查看MikeTex的答案,其中找到了一个健壮的方法:How to wait until matplotlib animation ends?

  • 4

    在我的系统上show()没有阻塞,虽然我希望脚本在继续之前等待用户与图形交互(并使用'pick_event'回调收集数据) .

    为了阻止执行直到绘图窗口关闭,我使用了以下内容:

    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    ax.plot(x,y)
    
    # set processing to continue when window closed
    def onclose(event):
        fig.canvas.stop_event_loop()
    fig.canvas.mpl_connect('close_event', onclose)
    
    fig.show() # this call does not block on my system
    fig.canvas.start_event_loop_default() # block here until window closed
    
    # continue with further processing, perhaps using result from callbacks
    

    但请注意,canvas.start_event_loop_default()会产生以下警告:

    C:\Python26\lib\site-packages\matplotlib\backend_bases.py:2051: DeprecationWarning: Using default event loop until function specific to this GUI is implemented
      warnings.warn(str,DeprecationWarning)
    

    虽然脚本仍在运行 .

  • 6
    plt.figure(1)
    plt.imshow(your_first_image)
    
    plt.figure(2)
    plt.imshow(your_second_image)
    
    plt.show(block=False) # That's important 
    
    raw_input("Press ENTER to exist") # Useful when you run your Python script from the terminal and you want to hold the running to see your figures until you press Enter
    
  • 20

    我还必须将 plt.pause(0.001) 添加到我的代码中以使其在for循环中正常工作(否则它只显示第一个和最后一个绘图):

    import matplotlib.pyplot as plt
    
    plt.scatter([0], [1])
    plt.draw()
    plt.show(block=False)
    
    for i in range(10):
        plt.scatter([i], [i+1])
        plt.draw()
        plt.pause(0.001)
    
  • 176

    您可能希望在 matplotlib 的文档中阅读本文档, Headers 为:

    Using matplotlib in a python shell

  • 7

    这是一个更新(Windows 10上的python 3.6.5) .

    我尝试了各种组合 - 最简单的我发现只是在每个绘图后使用 pause(0.01) - 中间图不需要 show() - 然后最后一个 show() 确保您可以在终止前查看最终的绘图 .

    作为一个例子,这里有一些代码我用来检查各种数组大小的速度 - 更高的绘图值是更高的速度......有10个重叠的图...

    from pylab import *
    import matplotlib.pyplot as plt
    from time import *
    ttot=clock();
    mmax=6;npts=20;nplts=10;
    x=[int(a+0.5) for a in 10**linspace(0,mmax,npts)]
    for nrun in range(nplts):
        j=0;aa=1;bb=1;b=1;
        tim=zeros(npts)
        for n in x:
            aa=rand(n);bb=aa;b=aa;
            if n<100:m=10000
            elif n<5000:m=1000
            elif n<20000:m=100
            else:m=100
            tt=clock()
            for ii in range(1,m+1):
              b=aa*bb+aa
            tt1=clock()-tt
            tim[j]=tt1/n/m
            j=j+1
        print(n,2/(tt1/n/m)/1e6);
        plt.semilogx(x,2/tim/1e6)
        pause(0.01)
    print(clock()-ttot)
    show()
    
  • 0

    如果您在控制台中工作,即 IPython ,您可以使用其他答案中指出的 plt.show(block=False) . 但如果你很懒,你可以输入:

    plt.show(0)
    

    哪个都一样 .

  • 5

    如果我理解正确的问题,使用Ipython(或Ipython QT或Ipython笔记本)将允许您与图表交互工作,而计算在后台进行 . http://ipython.org/

  • 5

    如果你想打开多个数字,同时保持它们全部打开,这段代码对我有用:

    show(block=False)
    draw()
    
  • 0

    如果它支持以 non-blocking 方式使用,最好始终检查您正在使用的库 .

    但是如果你想要一个更通用的解决方案,或者没有其他办法,你可以使用python中包含的multprocessing模块运行在分离进程中阻塞的任何东西 . 计算将继续:

    from multiprocessing import Process
    from matplotlib.pyplot import plot, show
    
    def plot_graph(*args):
        for data in args:
            plot(data)
        show()
    
    p = Process(target=plot_graph, args=([1, 2, 3],))
    p.start()
    
    print 'yay'
    print 'computation continues...'
    print 'that rocks.'
    
    print 'Now lets wait for the graph be closed to continue...:'
    p.join()
    

    这有启动新流程的开销,并且有时在复杂的情况下更难调试,所以我更喜欢其他解决方案(使用 matplotlibnonblocking API calls

  • 2

    我还希望我的绘图显示运行其余代码(然后继续显示),即使出现错误(我有时会使用绘图进行调试) . 我编写了这个小小的黑客,以便这个 with 语句中的任何图表都是这样的 .

    这可能有点太不标准,不适用于 生产环境 代码 . 这段代码中可能存在很多隐藏的“陷阱” .

    from contextlib import contextmanager
    
    @contextmanager
    def keep_plots_open(keep_show_open_on_exit=True, even_when_error=True):
        '''
        To continue excecuting code when plt.show() is called
        and keep the plot on displaying before this contex manager exits
        (even if an error caused the exit).
        '''
        import matplotlib.pyplot
        show_original = matplotlib.pyplot.show
        def show_replacement(*args, **kwargs):
            kwargs['block'] = False
            show_original(*args, **kwargs)
        matplotlib.pyplot.show = show_replacement
    
        pylab_exists = True
        try:
            import pylab
        except ImportError: 
            pylab_exists = False
        if pylab_exists:
            pylab.show = show_replacement
    
        try:
            yield
        except Exception, err:
            if keep_show_open_on_exit and even_when_error:
                print "*********************************************"
                print "Error early edition while waiting for show():" 
                print "*********************************************"
                import traceback
                print traceback.format_exc()
                show_original()
                print "*********************************************"
                raise
        finally:
            matplotlib.pyplot.show = show_original
            if pylab_exists:
                pylab.show = show_original
        if keep_show_open_on_exit:
            show_original()
    
    # ***********************
    # Running example
    # ***********************
    import pylab as pl
    import time
    if __name__ == '__main__':
        with keep_plots_open():
            pl.figure('a')
            pl.plot([1,2,3], [4,5,6])     
            pl.plot([3,2,1], [4,5,6])
            pl.show()
    
            pl.figure('b')
            pl.plot([1,2,3], [4,5,6])
            pl.show()
    
            time.sleep(1)
            print '...'
            time.sleep(1)
            print '...'
            time.sleep(1)
            print '...'
            this_will_surely_cause_an_error
    

    如果/当我实现正确的“保持图表打开(即使发生错误)并允许显示新图”时,我希望脚本在没有用户干扰的情况下正确退出(为了批处理执行目的) .

    我可能会使用来自https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interruption-implementation的超时问题"End of script! \nPress p if you want the plotting output to be paused (you have 5 seconds): " .

  • 2

    在我的情况下,我想在计算时弹出几个窗口 . 作为参考,这是方式:

    from matplotlib.pyplot import draw, figure, show
    f1, f2 = figure(), figure()
    af1 = f1.add_subplot(111)
    af2 = f2.add_subplot(111)
    af1.plot([1,2,3])
    af2.plot([6,5,4])
    draw() 
    print 'continuing computation'
    show()
    

    PS . 一个非常有用的guide to matplotlib's OO interface .

相关问题