我编写了一个Python脚本,该脚本应该运行一个循环,该循环从标准输入中读取3d坐标,并在上以散点图的形式显示最近读取的坐标mpl_toolkits.mplot3d.Axes3D
。
当我通过提示符手动输入坐标时,它可以工作(尽管会给出一些弃用警告):
$ 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
工作行为是,打开图形窗口,该窗口显示一个散点图,该散点图显示一个点。不起作用是,图形窗口已打开,但仅显示灰色背景,没有轴或点。
这是绘图脚本的代码:
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'
我可以使用matplotlib版本1.4.3和python 2.7复制。原因似乎是由于pythonstdin
读取函数阻塞直到管道关闭(此处所述),
这个问题的根源在于在Python中实现这些阅读机制的方式(请参阅Python的问题跟踪器中有关此问题的讨论)。在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()
您需要sys.stdout.flush()
在中打印后添加generate3d.py
。
现在看来似乎应该是可以设置O_NONBLOCK
标志sys.stdin
的东西,如flags = fcntl(sys.stdin, F_GETFL)
和fcntl(sys.stdin, F_SETFL, flags | O_NONBLOCK)
。但是,这对我不起作用。根据错误跟踪器,我认为这在python 3.0中不再是问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句