Is there a way to detach matplotlib plots so that the computation can continue?
在python解释器中的这些指令之后,会得到一个带有绘图的窗口:
1 2 3 4 | from matplotlib.pyplot import * plot([1,2,3]) show() # other code |
不幸的是,我不知道如何在程序进行进一步计算的同时,继续交互地探索
有可能吗?有时计算时间很长,如果在检查中间结果的过程中继续进行计算,会有所帮助。
使用不会阻塞的
使用
1 2 3 4 5 6 7 | 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() |
号
使用交互模式:
1 2 3 4 5 6 7 8 | 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() |
使用关键字"block"重写阻塞行为,例如
1 2 3 4 5 6 | from matplotlib.pyplot import show, plot plot(1) show(block=False) # your code |
继续您的代码。
如果它以非阻塞方式支持使用,那么最好始终检查正在使用的库。
但是,如果您想要一个更通用的解决方案,或者没有其他方法,那么您可以使用Python中包含的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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() |
这会导致启动一个新进程的开销,有时在复杂的场景中很难进行调试,因此我更喜欢另一种解决方案(使用
尝试
1 2 3 4 5 6 7 8 9 10 11 | 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. |
。
In non-interactive mode, display all figures and block until the figures have been closed; in interactive mode it has no effect unless figures were created prior to a change from non-interactive to interactive mode (not recommended). In that case it displays the figures but does not block.
A single experimental keyword argument,
block , may be set toTrue orFalse to override the blocking behavior described above.
号
您可能需要阅读
在python shell中使用matplotlib
重要事项:只是为了澄清一些事情。我假设命令在一个
对我来说,一个简单的方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 HERE ! ! ! ################################ # the next command is the last line of my script plt.show() |
在我的例子中,我希望在计算窗口时弹出几个窗口。参考方法如下:
1 2 3 4 5 6 7 8 9 | 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() |
。
对Matplotlib的OO接口非常有用的指南。
嗯,我很难找出非阻塞命令…但最后,我设法重新编写了"cookbook/matplotlib/animations-animating selected plot elements"示例,因此它可以处理线程(并通过全局变量或通过Ubuntu 10.04上的python 2.6.5上的多进程
脚本可以在这里找到:设置"选定"的动画"绘图元素-thread.py"-或者粘贴在下面(注释较少)以供参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 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! |
希望这能帮助别人,干杯!
如果您在控制台中工作,即
1 | plt.show(0) |
这是一样的。
在许多情况下,将图像保存为硬盘上的.png文件会更方便。原因如下:
优势:
- 你可以打开它,看看它,然后在这个过程中的任何时候关闭它。这在应用程序长时间运行时特别方便时间。
- 不会弹出任何东西,也不会强制打开窗口。这在处理许多数字时特别方便。
- 您的图像可供以后参考,关闭图形窗口时不会丢失。
- 我能想到的唯一一件事就是你必须自己去查找文件夹并打开图像。
小精灵
缺点:
小精灵
我还希望我的绘图显示运行其余代码(然后继续显示),即使有错误(我有时使用绘图进行调试)。我编写了这个小代码,以便在这个
这可能有点不标准,不适合生产代码。这段代码中可能隐藏了很多"gotchas"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 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 |
如果/当我执行正确的"保持绘图打开(即使发生错误)并允许显示新的绘图"时,如果没有用户干扰,我希望脚本正确退出(出于批处理执行目的)。
我可能会使用类似超时问题"脚本结束!如果您希望暂停打印输出(您有5秒钟):"来自https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interrupt-implementation。
我还必须在代码中添加
1 2 3 4 5 6 7 8 9 10 | 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) |
在我的系统上,show()不会阻塞,尽管我希望脚本在继续之前等待用户与图形交互(并使用"pick_event"回调收集数据)。
为了在绘图窗口关闭之前阻止执行,我使用了以下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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()生成了以下警告:
1 2 | 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) |
。
尽管剧本还在运行。
1 2 3 4 5 6 7 8 9 | 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 |
。
在我看来,这个线程中的答案提供了一些方法,这些方法不适用于每个系统,也不适用于更复杂的情况,如动画。我建议在下面的线程中查看miktex的答案,其中发现了一个健壮的方法:如何等待Matplotlib动画结束?
如果要打开多个数字,同时保持所有数字都打开,则此代码适用于我:
1 2 | show(block=False) draw() |
号