3

私は最近、Pythonと、Enthought Python Distribution(無料バージョン1)に同梱されているmatplotlibモジュール(1.1.0)をいじり始めました。私は自分にできる面白いプロジェクトを考えて、次のようなものを思いつきました。

  • インターネットアドレスのpingを取得します
  • sys.stdinそれをPythonスクリプトにパイプします

今pythonスクリプトで:

  • 回答時間がない場合は、回答時間を正規表現しますNaN。数値として0を使用します。
  • matplotlibを介してデータをプロットする
  • 継続的にデータを追加する

私はこれを介してpingを取得することができました:ping stackoverflow.com | pythonscript.pyはanswertimeを取得するのは特に難しいことではありませんでした。しかし、データのプロットに関しては。ハマった。matplotlib内にアニメーションモジュールがあることは知っていますが、タイマーベースのプロットはこれよりもプログラミングが難しいと思います。とにかくイベントがどのように使用されるかはわかりません。私が欲しいもの:

  • sys.stdinが新しい文字列を取得し、ping時間が取得されるのを待ちます
  • データ配列に追加します
  • データ配列をプロットしますが、それほど簡単ではないようです。これ以外に、エラー処理はまだ行われていません。残念ながら、私はそれについて多くのグーグルをしましたが、同等のコードを見つけることができませんでした:/多分このデザインはこのようなものではありません。

誰かがこの再プロットを達成する方法を知っていますか?pingは1秒ごとにしか届かないため、効率的である必要はありません。着信stdinをバッファリングして、通常のタイマーベースのプロットを実行することを考えましたが、今はそれを実行することを考えています。

前もって感謝します、

ジョナス

Update1:

次を使用して、このエラーを取り除くことができます。

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())
4

2 に答える 2

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())
于 2012-10-25T21:00:08.650 に答える
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を使用しない方がクリーンなはずです。matplotlibをGUIに埋め込む方法を調べるために、それは本当に簡単で、いくつかの異なるGUIツールキットで実行できます。

于 2012-09-01T13:55:26.360 に答える