matplotlib :(重新)绘制ping标准输入数据。可行?

时间:2012-09-01 13:22:24

标签: python matplotlib

我最近开始修改python和matthlotlib模块(1.1.0)随Enthought Python Distribution(免费版本1)一起提供。 我想到了一个我能做的有趣的项目,并想出了类似的东西:

  • 获取互联网地址
  • 通过sys.stdin管道进入python脚本

现在在python脚本中:

  • 正则表达式的答案时间,如果没有答案时间:使用NaN或仅使用0作为数字
  • 通过matplotlib绘制数据
  • 不断添加数据

我设法通过这个获得ping:ping stackoverflow.com | python script.py 得到answertime不是特别难。但是在绘制数据方面。我被卡住了。我知道matplotlib中有一个动画模块,但我认为基于计时器的绘图比这更难编程,我不知道如何使用事件。我想要的是什么:

  • 等待sys.stdin获取新字符串,从而获得ping时间
  • 将其添加到数据阵列
  • 绘制数据数组 但它似乎并不那么容易。除此之外,错误处理还没有完成.. 不幸的是我找不到任何类似的代码,虽然我做了很多关于它的谷歌搜索:/也许这个设计不是这样的..

有人知道如何完成这种重新绘制吗?它不需要高效,因为ping只是每隔一秒左右就会出现.. 我考虑过缓冲传入的标准输入并做一个基于计时器的常规情节,但我现在已经有了这个想法。

提前谢谢你,

纳斯

UPDATE1:

我可以通过使用:

来摆脱这个错误

l1.set_xdata(范围(LEN(数据)))

在l1.set_ydata(..)之前,但它仍然没有绘制任何内容,窗口也没有响应。至少它显示了绘图轴。

代码

import sys
import re
import numpy as np
import matplotlib.pyplot as plt


def main():
    if sys.stdin.isatty():
        print "Please use a pipe as stdin\nExample: ping stackoverflow.com | python script.py"
        return 0
    regex = re.compile('time=(\d+.\d+)')
    data = []
    fig = plt.figure()

    ax = fig.add_subplot(111)
    ax.set_yscale('linear') # or log
    ax.grid(True)

    l1, = ax.plot(data)
    fig.show()

    while True:
        #get ping, if no string: stream has ended
        line = sys.stdin.readline()
        if line == '':
            break
        #conversion: 64 bytes from 127.0.0.1: icmp_seq=0 ttl=45 time=100.873 ms --> 100.873
        match = regex.findall(line)
        number = 0.

        if len(match) > 1:
            raise ValueError()
        if len(match) == 1:
            try:
                number = float(match[0])
            except ValueError as e:
                print e
        #add number to array, plot the data
        data.append(number)
        l1.set_xdata(range(len(data)))
        l1.set_ydata(data)

        ax.relim()
        ax.autoscale()

        plt.draw()
        fig.canvas.flush_events()
    return 0

if __name__ == '__main__':
    sys.exit(main())

2 个答案:

答案 0 :(得分:2)

重新绘制数据似乎对我有用:

#!/usr/bin/python

import sys, re
import numpy as np
import matplotlib.pyplot as plt


def main():
    if sys.stdin.isatty():
        print "Please use a pipe as stdin\nExample: ping stackoverflow.com | python script.py"
        return 0
    regex = re.compile('time=(\d+.\d+)')

    data = [0]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    #l1, = ax.plot(data)
    fig.show()

    while True:
        #get ping, if no string: stream has ended
        line = sys.stdin.readline()
        if line == '':
            break
        #conversion: 64 bytes from 127.0.0.1: icmp_seq=0 ttl=45 time=100.873 ms --> 100.873
        match = regex.findall(line)
        number = 0.

        if len(match) > 1:
            raise ValueError()
        if len(match) == 1:
            try:
                number = float(match[0])
            except ValueError as e:
                print e
        #add number to array, plot the data
        data.append(number)
        l1, = ax.plot(data, 'r')
        plt.draw()
    return 0

if __name__ == '__main__':
        sys.exit(main())

答案 1 :(得分:1)

您首先拥有plt.show(),请不要使用它。而是在那里使用fig.show()。然后在你的循环中只有plt.draw()。其余的似乎很好。问题是plt.show()启动了一个主循环,锁定了进一步的执行(在图的事件之外)。 fig.show()似乎没有,但按钮可能不会像这样工作(我没试过)。

您必须添加自动缩放:

ax.relim()
ax.autoscale()
plt.draw()
# And this allows you to at least close the window (and crash the program by that ;))
fig.canvas.flush_events()

但实际上应该更清洁,不要使用pyplot。为了了解如何将embed matplotlib变成一个gui,它非常简单,并且可以用于几个不同的gui工具包。

相关问题