有没有办法分离 matplotlib 图以便计算可以继续?
-
19-08-2019 - |
题
在 Python 解释器中执行这些指令后,会出现一个带有绘图的窗口:
from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code
不幸的是,我不知道如何继续交互地探索由 show()
同时程序会进行进一步的计算。
有可能吗?有时计算很长,如果在检查中间结果时继续进行计算将会有所帮助。
解决方案
使用matplotlib
的调用,不会阻塞:
使用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()
其他提示
使用关键字“块”来覆盖阻挡行为,例如
from matplotlib.pyplot import show, plot
plot(1)
show(block=False)
# your code
继续代码。
最好始终检查您正在使用的库是否支持在 非阻塞 方式。
但是,如果您想要一个更通用的解决方案,或者没有其他方法,您可以使用以下命令在单独的进程中运行任何阻塞的内容: multprocessing
python 中包含的模块。计算将继续:
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()
这会产生启动新进程的开销,并且有时在复杂的情况下更难以调试,所以我更喜欢其他解决方案(使用 matplotlib
的 非阻塞 API 调用)
尝试
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()
文档表示:
在非交互模式时,显示所有图和块,直到数字已被关闭;在交互模式中它没有影响,除非数字是之前从非交互式到交互模式的变化创建(不推荐)。在这种情况下它显示数字,但不会阻止。
一个单一实验关键字参数,
block
,可以被设置为True
或False
覆盖上述阻塞行为。
您可能需要阅读matplotlib
文档中的这个文件,标题为:
重要:只是做什么清楚。我认为该命令的内部 .py
剧本和剧本是被称为使用例如 python script.py
从控制台。
一个简单的方式对我的作品是:
- 使用区块=False内显示: 专利法条约。显示(块=False)
- 使用 另一个 显示() 在结束 。py脚本。
例 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 HERE ! ! !
################################
# the next command is the last line of my script
plt.show()
在我的情况,我想有,因为他们正在计算几个窗口弹出。作为参考,这是这样的:
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。 href="https://github.com/ericliang/matplotlib/blob/master/branches/unit_support/htdocs/leftwich_tut.txt" rel="nofollow noreferrer">引导非常有用
好吧,我在弄清楚非阻塞命令时遇到了很大的困难......但最后,我成功地重新设计了“Cookbook/Matplotlib/Animations - 对选定的绘图元素进行动画处理“示例,因此它适用于线程(并通过全局变量或多进程在线程之间传递数据 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!
希望这对某人有帮助,
干杯!
在许多情况下它 更多的方便,直到保存的图像 作为一个。png文件的硬盘驱动器。这里就是为什么:
优点:
- 你可以打开它,看一看它和关闭任何时间的过程。这是特别方便的时候你的应用程序的运行长 时间。
- 什么都不会弹出来,你都不会被迫有的窗户打开。这是特别方便的时候你正在处理的许多数字。
- 你的图像可用于日后参考,并不是失去了时关闭图窗口。
缺点是:
- 我唯一能想到的是你要去取景器的文件夹和开放的图像自己。
如果您在控制台工作,即IPython
你可以使用plt.show(block=False)
在其他的答案中指出。但是,如果你懒,你可以只需键入:
plt.show(0)
,这将是相同的。
我不得不也加入plt.pause(0.001)
我的代码,以真正使内部的工作循环(否则它只会显示最初和最后的情节):
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)
我也想我的图来显示运行的代码的其余部分(然后保持上显示),即使存在错误(I有时使用重复用于调试)。我编写了这个小黑客,使这个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
如果/当我实现一个合适的“保留地块开(即使出现错误),并允许新的阴谋显示”,如果没有用户的干涉告诉它,否则(对批处理执行我希望脚本正确退出目的)。
我可以使用类似超时-问题“脚本结束\ n按p如果你想在绘图输出被暂停(你有5秒):”从的 https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-换用户输入中断的实现。
在我的系统展()不会阻止,但我想脚本等待用户与图形交互(和收集使用“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)
虽然脚本还是跑。
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动画结束?
如果你想打开多个图形,同时保持它们全部开通,该代码为我工作:
show(block=False)
draw()
在OP询问detatching matplotlib
图。大多数的答案从Python解释器内承担执行命令。这里介绍的用例是我在一个终端,其中一个file.py
运行测试代码(如bash)的偏好和您想要的曲线图(S)上来,但python脚本来完成,并返回到命令提示符。
此独立的文件使用multiprocessing
启动一个单独的工艺用于与matplotlib
绘图数据。使用os._exit(1)主线程退出href="https://stackoverflow.com/questions/24694763/how-to-let-the-child-process-live-when-parent-process-exited">这岗位。该os._exit()
力量主要退出,但离开matplotlib
子进程还活着,直到响应情节窗口关闭。它是一个独立的进程完全。
此方法是有点像与拿出一个响应命令提示图窗口一个Matlab发展会话。通过这种方法,你已经失去了与图形窗口过程中的所有接触,但是,这是确定的开发和调试。只要关闭该窗口,并保持测试。
multiprocessing
被设计用于蟒只执行代码,这使得它也许更适合比subprocess
。 multiprocessing
是跨平台的,所以这应该很少或没有调整在Windows或Mac工作。有没有需要检查底层操作系统。这是在Linux上测试的,Ubuntu 18.04LTS。
#!/usr/bin/python3
import time
import multiprocessing
import os
def plot_graph(data):
from matplotlib.pyplot import plot, draw, show
print("entered plot_graph()")
plot(data)
show() # this will block and remain a viable process as long as the figure window is open
print("exiting plot_graph() process")
if __name__ == "__main__":
print("starting __main__")
multiprocessing.Process(target=plot_graph, args=([1, 2, 3],)).start()
time.sleep(5)
print("exiting main")
os._exit(0) # this exits immediately with no cleanup or buffer flushing
运行file.py
带来了一个数字窗口,然后退出__main__
但是,因为它是一个独立的进程multiprocessing
+ matplotlib
图窗口保持响应与缩放,平移,和其他按钮。
检查过程在与bash命令提示:
ps ax|grep -v grep |grep file.py
使用plt.show(block=False)
,并在你的脚本调用plt.show()
结束。
这将确保当脚本完成窗口不会被关闭。