2016-10-28 5 views
0

標準入力から3次元座標を読み取り、最も最近読み込まれた座標を散布図としてmpl_toolkits.mplot3d.Axes3Dに表示するループを実行するはずのPythonスクリプトを作成しました。対話型プロットは、別のプログラムからパイプで入力して初期化できません

私は(それはしかし、いくつかの非推奨の警告を与える)プロンプトから手動で座標を入力すると、それは動作します:

$ python plot3d.py 
.5 .5 .5 
/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py:2407: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented 
    warnings.warn(str, mplDeprecation) 

私はプログラムにファイルから座標を供給するときにも動作します:

$ head generated 
0.56 0.40 0.55 
0.61 0.49 0.60 
0.48 0.39 0.48 
0.39 0.33 0.39 
0.32 0.28 0.32 
0.35 0.31 0.35 
0.50 0.47 0.50 
0.40 0.38 0.40 
0.37 0.35 0.37 
0.51 0.50 0.51 
$ python plot3d.py < generated 

しかし、生成スクリプトの出力をプロッティングスクリプトに直接パイプすると生成スクリプトは各反復後にtime.sleep()を実行します。

$ python generate3d.py | python plot3d.py 

動作ビヘイビアは、Figureウィンドウが開かれ、1つのドットを示す散布図が表示されます。動作しない動作は、Figureウィンドウが開かれますが、灰色の背景、軸やドットは表示されません。ここで

は、プロットスクリプトのコードです:ここで

from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 

plt.ion() 

fig = plt.figure() 
ax = fig.add_subplot(111, projection='3d') 

plotted_items = None 
while True: 
    if plotted_items is not None: 
     plotted_items.remove() 
    try: 
     x,y,z = map(float, raw_input().split()) 
    except: 
     break 
    else: 
     plotted_items = ax.scatter([x],[y],[z]) 
     ax.set_xlim(-5, 5) 
     ax.set_ylim(-5, 5) 
     ax.set_zlim(-5, 5) 
     plt.pause(0.1) 

は、生成スクリプトのコードです:

from random import random 
import time 

last = None 
while True: 
    if last is None: 
     last = [random(), random(), random()] 
    offset = random() 
    for i in range(len(last)): 
     last[i] += 0.25 * (offset - last[i]) 
    print "%.2f %.2f %.2f" % tuple(last) 
    # the value of this sleep duration influences how long it takes to initialize 
    # the plot in the other script!? 
    time.sleep(0.5) 

私は生成スクリプト内のスリープ時間の影響があるかもしれないことを観察しました軸の初期化に必要な時間に比例します。休止時間がゼロに近づくと、初期化時間はほとんど必要ありません。スリープ時間が0.1になると、すでにグラフが表示されるまでに時間がかかります。 私は、表示されたデータが最終的にそこにあるときのレイテンシについてまだ調べていません。

誰でもこの現象を再現できますか?誰も私がこれを理解して解決するのを助けることができる?私は何か間違っているのですか?

潜在的に有益な情報:

$ lsb_release -d 
Description: Ubuntu 14.04.5 LTS 
$ python --version 
Python 2.7.6 

>>> matplotlib.__version__ 
'1.3.1' 

答えて

1

私はmatplotlibのバージョン1.4.3とPython 2.7で再現することができます。その理由は、この問題の

起源は、これらの読みのメカニズムは、Pythonで実装されている方法である、パイプが閉じ(hereを説明)までブロックのpython stdin読み取り機能が原因のようです(Pythonの問題からdiscussion on this issueを参照してください。トラッカー)。 Python 2.7.6では、実装はCのstdioライブラリに依存しています。

彼らはリンクに使用ソリューションは、サブプロセスとしてgeneate3d.pyを実行して、ノンブロッキングフラグを設定することで、

from subprocess import Popen, PIPE 
import time 
from fcntl import fcntl, F_GETFL, F_SETFL 
from os import O_NONBLOCK, read 

from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 
import sys 

plt.ion() 

fig = plt.figure() 
ax = fig.add_subplot(111, projection='3d') 

# run the shell as a subprocess: 
p = Popen(['python', 'generate3d.py'], 
     stdin = PIPE, stdout = PIPE, stderr = PIPE, shell = False) 
# set the O_NONBLOCK flag of p.stdout file descriptor: 
flags = fcntl(p.stdout, F_GETFL) # get current p.stdout flags 
fcntl(p.stdout, F_SETFL, flags | O_NONBLOCK) 
# issue command: 
p.stdin.write('command\n') 
# let the shell output the result: 
time.sleep(0.1) 

plotted_items = None 
while True: 
    if plotted_items is not None: 
     try: 
      plotted_items.remove() 
     except ValueError: 
      print(plotted_items) 
      pass 
    try: 
     x,y,z = map(float, read(p.stdout.fileno(), 1024).split(' ')) 
    except OSError: 
     time.sleep(0.5) 
    except: 
     raise 
    else: 
     plotted_items = ax.scatter([x],[y],[z]) 
     ax.set_xlim(-5, 5) 
     ax.set_ylim(-5, 5) 
     ax.set_zlim(-5, 5) 
     plt.pause(0.1) 
     plt.draw() 

あなたはgenerate3d.pyで印刷した後sys.stdout.flush()を追加する必要があります。

フラグをsys.stdinに設定する必要がありました。flags = fcntl(sys.stdin, F_GETFL)fcntl(sys.stdin, F_SETFL, flags | O_NONBLOCK)のようになりました。しかし、これは私にとってはうまくいかない。私はこれがもうbug trackerによるpython 3.0の問題ではないと思います。

+0

感謝を!私は 'generate3d.py'でスリープする前に' sys.stdout.flush() 'を追加し、問題はなくなりました。プロセスをサブプロセスとして実行する必要はありません。 – moooeeeep

0

明らかに、標準出力の書き込みプロセスバッファは、特定のサイズに達するまでフラッシュされませんでした。明示的なフラッシュを追加しても問題が解決:

また
from random import random 
import time 
import sys 

last = None 
while True: 
    if last is None: 
     last = [random(), random(), random()] 
    offset = random() 
    for i in range(len(last)): 
     last[i] += 0.25 * (offset - last[i]) 
    print "%.2f %.2f %.2f" % tuple(last) 
    # flush before sleep to make sure the data is actually written on time 
    sys.stdout.flush() 
    time.sleep(1.0) 

、元のスクリプトはPythonのバッファなしモードで実行することができます:あなたの入力のための

$ python -u generate3d.py | python plot3d.py 
関連する問題