Matplotlib - 强制绘图并返回主代码

25
这是一个我想要的最小工作示例,改编自这个问题
from matplotlib.pyplot import plot, draw, show

def make_plot():
    plot([1,2,3])
    draw()
    print 'continue computation'

print('Do something before plotting.')
# Now display plot in a window
make_plot()

answer = raw_input('Back to main and window visible? ')
if answer == 'y':
    print('Excellent')
else:
    print('Nope')

show()

我希望的是:我调用函数绘制图形,然后图形窗口出现,并且我能回到提示符,这样我就可以输入一些值(基于刚刚显示的图像)并继续使用代码(窗口可以关闭或保留在那里,我不在意)。
实际上发生的是:只有在代码完成后才会出现包含图形的窗口,这并不好。
添加1:
我尝试了以下操作,但结果相同,即图形窗口出现在代码结尾而非之前。
from matplotlib.pyplot import plot, ion, draw

ion() # enables interactive mode
plot([1,2,3]) # result shows immediately (implicit draw())
# at the end call show to ensure window won't close.
draw()

answer = raw_input('Back to main and window visible? ')
if answer == 'y':
    print('Excellent')
else:
    print('Nope')

如果我将draw()更改为show(),结果是相同的。

加2

我尝试了以下方法:

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 'computation continues...'

print 'Now lets wait for the graph be closed to continue...:'
p.join()

这会导致在 Canopy 中出现 Python kernel has crashed 错误,并显示以下消息:

The kernel (user Python environment) has terminated with error code -6. This may be due to a bug in your code or in the kernel itself.

Output captured from the kernel process is shown below.

[IPKernelApp] To connect another client to this kernel, use:
[IPKernelApp] --existing /tmp/tmp9cshhw.json
QGtkStyle could not resolve GTK. Make sure you have installed the proper libraries.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: ../../src/xcb_io.c:274: poll_for_event: La declaración `!xcb_xlib_threads_sequence_lost' no se cumple.

我应该提到我正在运行基于Ubuntu 12.04的elementary OS中的Canopy。

添加3

还尝试了在这个问题中发布的解决方案:

import numpy
from matplotlib import pyplot as plt

if __name__ == '__main__':
    x = [1, 2, 3]
    plt.ion() # turn on interactive mode
    for loop in range(0,3):
        y = numpy.dot(x, loop)
        plt.figure()
        plt.plot(x,y)
        plt.show()
        _ = raw_input("Press [enter] to continue.")

这将在代码执行过程中(即用户按下[Enter]键)显示空的图形窗口,并且仅在代码完成后显示图像。
同一问题中的另一解决方案甚至不会显示绘图窗口:
import numpy
from matplotlib import pyplot as plt
if __name__ == '__main__':
    x = [1, 2, 3]
    plt.ion() # turn on interactive mode, non-blocking `show`
    for loop in range(0,3):
        y = numpy.dot(x, loop)
        plt.figure()   # create a new figure
        plt.plot(x,y)  # plot the figure
        plt.show()     # show the figure, non-blocking
        _ = raw_input("Press [enter] to continue.") # wait for input from the user
        plt.close()    # close the figure to show the next one.
4个回答

28
你可以使用plt.show(block=False),这将直接消除阻塞。
对于你的例子,代码可能是这样的。
from matplotlib.pyplot import plot, show

def make_plot():
    plot([1,2,3])
    show(block=False)
    print('continue computation')

print('Do something before plotting.')
# Now display plot in a window
make_plot()

answer = input('Back to main and window visible? ')
if answer == 'y':
    print('Excellent')
else:
    print('Nope')

1
这个例子在我的情况下不起作用,绘图窗口仍然出现在代码完成之后,而不是在我请求“answer”输入之前。也许这与我的IDE(Enthought的“Canopy v 1.0.1.1190”)有关? - Gabriel
哦,是的,这个功能只在最近的matplotlib版本中添加。它在我的matplotlib 1.2下运行良好。你有更新的机会吗? - David Zwicker
1
我对Canopy不是很了解,但你可以尝试通过import matplotlibmatplotlib.use('GTKAgg')或其他后端来查看是否可行。请注意,在导入任何其他绘图相关内容之前,这两行代码应该放在最前面。 - David Zwicker
1
这里是来自matplotlib的帮助文档:http://matplotlib.org/faq/usage_faq.html#what-is-a-backend。在谷歌搜索“matplotlib backend”也会指向一些有用的线程,比如这个:https://dev59.com/qm445IYBdhLWcg3wTIjm。 - David Zwicker
1
回答晚了,但遗憾的是没有一个后端起作用。我很困惑为什么 python 不允许在结束之前显示图表... - Gabriel
显示剩余4条评论

14

对我来说,提出的解决方案都不起作用。 我使用了三个不同的IDE PyCharmSpyderPyzo,在Python 3.6下使用(目前)最新的Matplotlib 2.1进行了测试。

对我有效的是使用plt.pause命令,虽然不是最优解:

import matplotlib.pyplot as plt

def make_plot():
    plt.plot([1, 2, 3])
#    plt.show(block=False)  # The plot does not appear.
#    plt.draw()             # The plot does not appear.
    plt.pause(0.1)          # The plot properly appears.
    print('continue computation')

print('Do something before plotting.')
# Now display plot in a window
make_plot()

answer = input('Back to main and window visible? ')
if answer == 'y':
    print('Excellent')
else:
    print('Nope')

2
谢谢!我知道这已经过时了,但是除了这个方法,我找不到其他解决方案,而且这个方法如此简单。 - Jeff
1
我不得不增加时间,因为我有很多行要显示,但这是我找到的唯一有效的解决方案 :-) - ReneBt
1
我很久以前就放弃了这个问题,但是刚刚尝试了你的答案,它有效,谢谢。 - ajsp
对我来说,使用暂停0.1无效。我必须增加到0.5,这意味着我必须等待很长时间才能看到绘图...但至少它可以工作。 - YuseqYaseq

1

我无法在Canopy中使其工作(至少目前为止),但我可以使用Geany IDE使代码运行得像我想要的那样。这是适合我的代码,它是对问题中第一个代码块进行的非常小的修改,在该修改中,show()命令从文件结尾移动到make_plot()命令下方:

from matplotlib.pyplot import plot, draw, show

def make_plot():
    plot([1,2,3])
    draw()
    print 'Plot displayed, waiting for it to be closed.'

print('Do something before plotting.')
# Now display plot in a window
make_plot()
# This line was moved up <----
show()

answer = raw_input('Back to main after plot window closed? ')
if answer == 'y':
    print('Move on')
else:
    print('Nope')

它并不完全符合我的要求,但足够接近:它向用户显示一个图表,等待该图表窗口关闭,然后继续执行代码。理想情况下,它不应该等到图表窗口关闭才能继续执行代码,但我认为这比没有好。
上面的添加2部分中的代码也以同样的方式工作,并且不需要在Geany中进行任何修改,但我更喜欢这个方法,因为它更简单。如果我(什么时候)让它与Canopy一起工作,我会更新这个答案。

0
这对我来说可以运行,虽然不是最佳选择。 #!/usr/bin/env python3
import matplotlib.pyplot as plt

def make_plot():
    plt.plot([1, 2, 3])
    plt.show(block=False)
    input('Back to main and window visible? ') #Here is the trick
    print('continue computation')

print('Do something before plotting.')
# Now display plot in a window
make_plot()


answer = input('Quit now ?')
if answer == 'y':
    print('Excellent')
else:
    print('Nope')

你是想提出一个新问题还是为现有问题提供解决方案?如果你想提出一个新问题,请创建一个问题 - undefined
请创建一个新的问题来表达您的关注,不要将其作为对另一个问题的回答发布! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接