首页 文章

使用Matplotlib以非阻塞方式绘图

提问于
浏览
68

在过去的几天里,我一直在玩Numpy和matplotlib . 我在尝试使matplotlib绘制函数而不阻塞执行时遇到问题 . 我知道在这里已经有很多线索提出类似的问题了,我已经搜索了很多但是还没有成功完成这项工作 .

我曾经尝试过使用show(block = False),但我得到的只是一个冻结的窗口 . 如果我只是调用show(),则会正确绘制结果,但会阻止执行直到窗口关闭 . 从我读过的其他主题,我怀疑show(block = False)是否有效取决于后端 . 它是否正确?我的后端是Qt4Agg . 你能看看我的代码并告诉我你是否看错了吗?这是我的代码 . 谢谢你的帮助 .

from math import *
from matplotlib import pyplot as plt
print plt.get_backend()



def main():
    x = range(-50, 51, 1)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4

        y = [Xi**pow for Xi in x]
        print y

        plt.plot(x, y)
        plt.draw()
        #plt.show()             #this plots correctly, but blocks execution.
        plt.show(block=False)   #this creates an empty frozen window.
        _ = raw_input("Press [enter] to continue.")


if __name__ == '__main__':
    main()

PS . 我忘了说我想在每次绘制内容时更新现有窗口,而不是创建一个新窗口 .

4 回答

  • 94

    我花了很长时间寻找解决方案,并找到this answer .

    看起来,为了得到你(和我)想要的东西,你需要 plt.ion()plt.show() (不是 blocking=False ,不赞成使用),最重要的是 plt.pause(.001) (或者你想要的任何时间)的组合 . 需要pause,因为GUI事件在主代码休眠时发生,包括绘图 . 它's possible that this is implemented by picking up time from a sleeping thread, so maybe IDEs mess with that—I don't知道 .

    这是一个适用于python 3.5的实现:

    import numpy as np
    from matplotlib import pyplot as plt
    
    def main():
        plt.axis([-50,50,0,10000])
        plt.ion()
        plt.show()
    
        x = np.arange(-50, 51)
        for pow in range(1,5):   # plot x^1, x^2, ..., x^4
            y = [Xi**pow for Xi in x]
            plt.plot(x, y)
            plt.draw()
            plt.pause(0.001)
            input("Press [enter] to continue.")
    
    if __name__ == '__main__':
        main()
    
  • 0

    一个对我有用的简单技巧如下:

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

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


    Example

    import matplotlib.pyplot as plt
    
    plt.imshow(add_something)
    plt.xlabel("x")
    plt.ylabel("y")
    
    plt.show(block=False)
    
    #more code here (e.g. do calculations and use print to see them on the screen
    
    plt.show()
    

    Noteplt.show() 是我脚本的最后一行 .

  • 11

    您可以通过将绘图写入数组,然后在不同的线程中显示数组来避免阻止执行 . 以下是使用pyformulas 0.2.8中的pf.screen同时生成和显示绘图的示例:

    import pyformulas as pf
    import matplotlib.pyplot as plt
    import numpy as np
    import time
    
    fig = plt.figure()
    
    canvas = np.zeros((480,640))
    screen = pf.screen(canvas, 'Sinusoid')
    
    start = time.time()
    while True:
        now = time.time() - start
    
        x = np.linspace(now-2, now, 100)
        y = np.sin(2*np.pi*x) + np.sin(3*np.pi*x)
        plt.xlim(now-2,now+1)
        plt.ylim(-3,3)
        plt.plot(x, y, c='black')
    
        # If we haven't already shown or saved the plot, then we need to draw the figure first...
        fig.canvas.draw()
    
        image = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
        image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))
    
        screen.update(image)
    
    #screen.close()
    

    结果:

    Sine animation

    免责声明:我是pyformulas的维护者 .

    参考:Matplotlib: save plot to numpy array

  • 7

    实时绘图

    import numpy as np
    import matplotlib.pyplot as plt
    
    x = np.linspace(0, 2 * np.pi, 100)
    # plt.axis([x[0], x[-1], -1, 1])      # disable autoscaling
    for point in x:
        plt.plot(point, np.sin(2 * point), '.', color='b')
        plt.draw()
        plt.pause(0.01)
    # plt.clf()                           # clear the current figure
    

    如果数据量太大,您可以使用简单的计数器降低更新速率

    cnt += 1
    if (cnt == 10):       # update plot each 10 points
        plt.draw()
        plt.pause(0.01)
        cnt = 0
    

    程序退出后

    保持图

    这是我无法找到满意答案的实际问题,我希望在脚本完成后没有关闭的绘图(如MATLAB),

    如果你考虑一下,在脚本完成之后,程序就会被终止,没有合理的方法来保存这个图,所以有两种选择

    • 阻止脚本退出(这是plt.show()而不是我想要的)

    • 在单独的线程上运行绘图(太复杂)

    这对我来说并不令人满意,所以我发现了另一种解决方案

    SaveToFile和外部查看器中的查看

    为此,保存和查看应该都很快,并且查看器不应该锁定文件和 should update the content automatically

    选择保存格式

    基于矢量的格式既小又快

    • SVG 很好,但除了网页浏览器默认需要手动更新外,没有找到好的浏览器

    • PDF 可以支持矢量格式,并且有支持实时更新的轻量级查看器

    具有实时更新的快速轻量级查看器

    对于 PDF ,有几个不错的选择

    • 在Windows上我使用SumatraPDF这是免费的,快速的和轻的(我的情况下只使用1.8MB RAM)

    • 在Linux上有几个选项,如Evince(GNOME)和Ocular(KDE)

    示例代码和结果

    用于将绘图输出到文件的示例代码

    import numpy as np
    import matplotlib.pyplot as plt
    
    x = np.linspace(0, 2 * np.pi, 100)
    y = np.sin(2 * x)
    plt.plot(x, y)
    plt.savefig("fig.pdf")
    

    首次运行后,打开上面提到的一个查看器中的输出文件并欣赏 .

    这是VSCode和SumatraPDF一起的截图,也是这个过程足够快以获得半实时更新率(我的设置可以接近10Hz,只需在间隔之间使用 time.sleep()
    pyPlot,Non-Blocking

相关问题