我最近开始修补 Python 和 Enthought Python Distribution(免费版本之一)附带的 matplotlib 模块(1.1.0)。我想到了一个我可以做的有趣的项目,并想出了这样的事情:
- 获取互联网地址的 ping
- 通过管道将其sys.stdin导入python脚本
现在在python脚本中:
- 正则表达式回答时间,如果没有回答时间:使用NaNor 只是 0 作为数字
- 通过 matplotlib 绘制数据
- 不断添加数据
我设法通过以下方式获得 ping:ping stackoverflow.com | python script.py 得到应答时间并不是特别难。但是在绘制数据时。我被困住了。我知道 matplotlib 中有一个动画模块,但我认为基于计时器的绘图会比这更难编程,而且我不知道如何使用事件。我想要的是:
- 等待 sys.stdin 获得一个新字符串,从而获得 ping 时间
- 将其添加到数据数组
- 绘制数据数组 但似乎没那么容易。除此之外,错误处理还没有完成。不幸的是我找不到任何类似的代码,虽然我做了很多谷歌搜索:/也许这个设计不是这样的。。
有谁知道如何完成这个重新绘制?它不需要高效,因为 ping 每隔一秒左右才会出现一次。我考虑过缓冲传入的标准输入并执行基于计时器的常规绘图,但我现在有了这样做的想法。
先感谢您,
乔纳斯
更新1:
我可以使用以下方法消除此错误:
l1.set_xdata(range(len(data)))
之前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())